<!DOCTYPE HTML>
<html lang="zh-CN">


<head>
    <meta charset="utf-8">
    <meta name="keywords" content="java并发编程从0到n, Max|Blog">
    <meta name="description" content="life is a fucking movie">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="renderer" content="webkit|ie-stand|ie-comp">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <!-- Global site tag (gtag.js) - Google Analytics -->


    <title>java并发编程从0到n | Max|Blog</title>
    <link rel="icon" type="image/png" href="/favicon.png">

    <link rel="stylesheet" type="text/css" href="/libs/awesome/css/all.css">
    <link rel="stylesheet" type="text/css" href="/libs/materialize/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/aos/aos.css">
    <link rel="stylesheet" type="text/css" href="/libs/animate/animate.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/lightGallery/css/lightgallery.min.css">
    <link rel="stylesheet" type="text/css" href="/css/matery.css">
    <link rel="stylesheet" type="text/css" href="/css/my.css">

    <script src="/libs/jquery/jquery.min.js"></script>

<meta name="generator" content="Hexo 5.3.0"><link rel="alternate" href="/atom.xml" title="Max|Blog" type="application/atom+xml">
</head>




<body>
    <header class="navbar-fixed">
    <nav id="headNav" class="bg-color nav-transparent">
        <div id="navContainer" class="nav-wrapper container">
            <div class="brand-logo">
                <a href="/" class="waves-effect waves-light">
                    
                    <img src="/medias/logo.png" class="logo-img" alt="LOGO">
                    
                    <span class="logo-span">Max|Blog</span>
                </a>
            </div>
            

<a href="#" data-target="mobile-nav" class="sidenav-trigger button-collapse"><i class="fas fa-bars"></i></a>
<ul class="right nav-menu">
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/" class="waves-effect waves-light">
      
      <i class="fas fa-home" style="zoom: 0.6;"></i>
      
      <span>首页</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/tags" class="waves-effect waves-light">
      
      <i class="fas fa-tags" style="zoom: 0.6;"></i>
      
      <span>标签</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/categories" class="waves-effect waves-light">
      
      <i class="fas fa-bookmark" style="zoom: 0.6;"></i>
      
      <span>分类</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/archives" class="waves-effect waves-light">
      
      <i class="fas fa-archive" style="zoom: 0.6;"></i>
      
      <span>归档</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/about" class="waves-effect waves-light">
      
      <i class="fas fa-user-circle" style="zoom: 0.6;"></i>
      
      <span>关于</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/contact" class="waves-effect waves-light">
      
      <i class="fas fa-comments" style="zoom: 0.6;"></i>
      
      <span>留言板</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/friends" class="waves-effect waves-light">
      
      <i class="fas fa-address-book" style="zoom: 0.6;"></i>
      
      <span>友情链接</span>
    </a>
    
  </li>
  
  <li>
    <a href="#searchModal" class="modal-trigger waves-effect waves-light">
      <i id="searchIcon" class="fas fa-search" title="搜索" style="zoom: 0.85;"></i>
    </a>
  </li>
</ul>


<div id="mobile-nav" class="side-nav sidenav">

    <div class="mobile-head bg-color">
        
        <img src="/medias/logo.png" class="logo-img circle responsive-img">
        
        <div class="logo-name">Max|Blog</div>
        <div class="logo-desc">
            
            life is a fucking movie
            
        </div>
    </div>

    

    <ul class="menu-list mobile-menu-list">
        
        <li class="m-nav-item">
	  
		<a href="/" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-home"></i>
			
			首页
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/tags" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-tags"></i>
			
			标签
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/categories" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-bookmark"></i>
			
			分类
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/archives" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-archive"></i>
			
			归档
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/about" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-user-circle"></i>
			
			关于
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/contact" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-comments"></i>
			
			留言板
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/friends" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-address-book"></i>
			
			友情链接
		</a>
          
        </li>
        
        
        <li><div class="divider"></div></li>
        <li>
            <a href="https://github.com/zhy2021/zhy2021.github.io" class="waves-effect waves-light" target="_blank">
                <i class="fab fa-github-square fa-fw"></i>Fork Me
            </a>
        </li>
        
    </ul>
</div>


        </div>

        
            <style>
    .nav-transparent .github-corner {
        display: none !important;
    }

    .github-corner {
        position: absolute;
        z-index: 10;
        top: 0;
        right: 0;
        border: 0;
        transform: scale(1.1);
    }

    .github-corner svg {
        color: #0f9d58;
        fill: #fff;
        height: 64px;
        width: 64px;
    }

    .github-corner:hover .octo-arm {
        animation: a 0.56s ease-in-out;
    }

    .github-corner .octo-arm {
        animation: none;
    }

    @keyframes a {
        0%,
        to {
            transform: rotate(0);
        }
        20%,
        60% {
            transform: rotate(-25deg);
        }
        40%,
        80% {
            transform: rotate(10deg);
        }
    }
</style>

<a href="https://github.com/zhy2021/zhy2021.github.io" class="github-corner tooltipped hide-on-med-and-down" target="_blank"
   data-tooltip="Fork Me" data-position="left" data-delay="50">
    <svg viewBox="0 0 250 250" aria-hidden="true">
        <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
        <path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
              fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
        <path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
              fill="currentColor" class="octo-body"></path>
    </svg>
</a>
        
    </nav>

</header>

    



<div class="bg-cover pd-header post-cover" style="background-image: url('/medias/featureimages/6.jpg')">
    <div class="container" style="right: 0px;left: 0px;">
        <div class="row">
            <div class="col s12 m12 l12">
                <div class="brand">
                    <h1 class="description center-align post-title">java并发编程从0到n</h1>
                </div>
            </div>
        </div>
    </div>
</div>




<main class="post-container content">

    
    <link rel="stylesheet" href="/libs/tocbot/tocbot.css">
<style>
    #articleContent h1::before,
    #articleContent h2::before,
    #articleContent h3::before,
    #articleContent h4::before,
    #articleContent h5::before,
    #articleContent h6::before {
        display: block;
        content: " ";
        height: 100px;
        margin-top: -100px;
        visibility: hidden;
    }

    #articleContent :focus {
        outline: none;
    }

    .toc-fixed {
        position: fixed;
        top: 64px;
    }

    .toc-widget {
        width: 345px;
        padding-left: 20px;
    }

    .toc-widget .toc-title {
        padding: 35px 0 15px 17px;
        font-size: 1.5rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    .toc-widget ol {
        padding: 0;
        list-style: none;
    }

    #toc-content {
        padding-bottom: 30px;
        overflow: auto;
    }

    #toc-content ol {
        padding-left: 10px;
    }

    #toc-content ol li {
        padding-left: 10px;
    }

    #toc-content .toc-link:hover {
        color: #42b983;
        font-weight: 700;
        text-decoration: underline;
    }

    #toc-content .toc-link::before {
        background-color: transparent;
        max-height: 25px;

        position: absolute;
        right: 23.5vw;
        display: block;
    }

    #toc-content .is-active-link {
        color: #42b983;
    }

    #floating-toc-btn {
        position: fixed;
        right: 15px;
        bottom: 76px;
        padding-top: 15px;
        margin-bottom: 0;
        z-index: 998;
    }

    #floating-toc-btn .btn-floating {
        width: 48px;
        height: 48px;
    }

    #floating-toc-btn .btn-floating i {
        line-height: 48px;
        font-size: 1.4rem;
    }
</style>
<div class="row">
    <div id="main-content" class="col s12 m12 l9">
        <!-- 文章内容详情 -->
<div id="artDetail">
    <div class="card">
        <div class="card-content article-info">
            <div class="row tag-cate">
                <div class="col s7">
                    
                    <div class="article-tag">
                        
                            <a href="/tags/%E5%B9%B6%E5%8F%91/">
                                <span class="chip bg-color">并发</span>
                            </a>
                        
                    </div>
                    
                </div>
                <div class="col s5 right-align">
                    
                    <div class="post-cate">
                        <i class="fas fa-bookmark fa-fw icon-category"></i>
                        
                            <a href="/categories/%E5%B9%B6%E5%8F%91/" class="post-category">
                                并发
                            </a>
                        
                    </div>
                    
                </div>
            </div>

            <div class="post-info">
                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-minus fa-fw"></i>发布日期:&nbsp;&nbsp;
                    2020-10-29
                </div>
                

                

                
                <div class="info-break-policy">
                    <i class="far fa-file-word fa-fw"></i>文章字数:&nbsp;&nbsp;
                    14.7k
                </div>
                

                
                <div class="info-break-policy">
                    <i class="far fa-clock fa-fw"></i>阅读时长:&nbsp;&nbsp;
                    58 分
                </div>
                

                
                    <div id="busuanzi_container_page_pv" class="info-break-policy">
                        <i class="far fa-eye fa-fw"></i>阅读次数:&nbsp;&nbsp;
                        <span id="busuanzi_value_page_pv"></span>
                    </div>
				
            </div>
        </div>
        <hr class="clearfix">

        
        <!-- 是否加载使用自带的 prismjs. -->
        <link rel="stylesheet" href="/libs/prism/prism.css">
        

        

        <div class="card-content article-card-content">
            <div id="articleContent">
                <h1 id="并发编程"><a href="#并发编程" class="headerlink" title="并发编程"></a>并发编程</h1><h2 id="1-进程与线程"><a href="#1-进程与线程" class="headerlink" title="1. 进程与线程"></a>1. 进程与线程</h2><h3 id="1-1-进程"><a href="#1-1-进程" class="headerlink" title="1.1 进程"></a>1.1 进程</h3><ul>
<li>进程可以视为程序的一个实例，大部分程序可以同时运行多个实例进程，也有程序只能启动一个实例进程</li>
<li>程序由指令和数据组成，这些指令要运行，数据要读写，就必须将指令加载至cpu，数据加载至内存，在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理io的。</li>
<li>进程被运行的时候，从磁盘加载这个程序的代码到内存，这时候就开启了一个进程。</li>
</ul>
<hr>
<h3 id="1-2-线程"><a href="#1-2-线程" class="headerlink" title="1.2 线程"></a>1.2 线程</h3><ul>
<li>一个进程之间可以分为1到多个线程</li>
<li>一个线程是一个指令流，将指令流中的一条条指令以一定的顺序交给cpu执行</li>
<li>java中，线程作为最小调度单位，进程作为资源分配的最小单位。在Windows中进程是不活动的，只是作为线程的容器。</li>
</ul>
<hr>
<h3 id="1-3-二者对比"><a href="#1-3-二者对比" class="headerlink" title="1.3 二者对比"></a>1.3 二者对比</h3><ul>
<li>进程之间相互独立，线程存在于进程内</li>
<li>进程拥有共享的资源，如内存空间，供其内部的线程共享</li>
<li>进程间通信较为复杂<ul>
<li>同一台计算机的进程通信叫做IPC（inter process communication）</li>
<li>不同计算机之间的进程通信，需要通过网络，并遵守共同的协议</li>
</ul>
</li>
<li>线程通信相对简单，他们共享进程的内存，就好比多个线程访问同一个变量</li>
<li>线程更轻量，线程上下文切换成本一般要比进程上下文切换低</li>
</ul>
<hr>
<h3 id="1-4-并行与并发"><a href="#1-4-并行与并发" class="headerlink" title="1.4 并行与并发"></a>1.4 并行与并发</h3><h4 id="并发"><a href="#并发" class="headerlink" title="并发"></a>并发</h4><blockquote>
<p>同一时间应对多件事情的能力</p>
</blockquote>
<p>一个cpu，单核心在同一之间段内在线程中来回调度，叫做并发</p>
<h4 id="并行"><a href="#并行" class="headerlink" title="并行"></a>并行</h4><blockquote>
<p>同一时间动手做多件事情的能力</p>
</blockquote>
<p>多个cpu或者多个核心，在同一时刻内同时工作两个以上的线程</p>
<p><img src="https://s1.ax1x.com/2020/10/29/BGZFQU.png" alt="BGZFQU.png"></p>
<hr>
<h3 id="1-5-应用"><a href="#1-5-应用" class="headerlink" title="1.5 应用"></a>1.5 应用</h3><p><strong>异步调用</strong></p>
<blockquote>
<p>多线程可以让方法执行变为异步的，比如说读取磁盘文件时，假设读取操作花费了5s，如果没有线程调度机制，这5s调用者啥也做不了，其他代码还得暂停</p>
</blockquote>
<p>结论：</p>
<ul>
<li>在项目中，视频文件需要转换格式等操作比较费时，这时可以开一个新的线程处理视频切换，避免阻塞主线程</li>
<li>ui程序中，开线程进行其他操作，避免ui线程阻塞</li>
</ul>
<hr>
<p><strong>提高效率</strong></p>
<ul>
<li><p>单核cpu下多线程不能实际提高程序运行效率，只是为了能够在不同的任务之间切换，不同线程轮流使用cpu，不至于一个线程总占用cpu，别的线程啥也不干</p>
</li>
<li><p>多核cpu可以并行跑多个线程，有的任务经过精心设计，拆分后可以并行执行，提高效率，但有的任务就没必要拆分。</p>
</li>
<li><p>IO操作不占用cpu，只是我们一般copy文件使用的是【阻塞IO】，这时相当于线程虽然不用cpu，但需要一直等待IO操作，没能充分利用线程。</p>
</li>
</ul>
<hr>
<h2 id="2-Java线程"><a href="#2-Java线程" class="headerlink" title="2. Java线程"></a>2. Java线程</h2><h3 id="2-1-创建和运行线程"><a href="#2-1-创建和运行线程" class="headerlink" title="2.1 创建和运行线程"></a>2.1 创建和运行线程</h3><h4 id="方法一：直接使用Thread"><a href="#方法一：直接使用Thread" class="headerlink" title="方法一：直接使用Thread"></a>方法一：直接使用Thread</h4><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">Thread</span> thread <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"running"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">;</span>

thread<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span><span class="token string">"t1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
thread<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"running"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h4 id="方法二：使用Runnable配合Thread"><a href="#方法二：使用Runnable配合Thread" class="headerlink" title="方法二：使用Runnable配合Thread"></a>方法二：使用Runnable配合Thread</h4><blockquote>
<p>把【线程】和【任务】分开</p>
<ul>
<li>Thread代表线程</li>
<li>Runnable重写run方法，做可运行的任务</li>
</ul>
</blockquote>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">Runnable</span> runnable <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Runnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"run方法"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">;</span>

<span class="token class-name">Thread</span> thread <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span>runnable<span class="token punctuation">,</span><span class="token string">"t2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

thread<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"main方法"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p><strong>Lambda表达式可以简化代码</strong></p>
<h4 id="方法三：FutureTask创建"><a href="#方法三：FutureTask创建" class="headerlink" title="方法三：FutureTask创建"></a>方法三：FutureTask创建</h4><blockquote>
<p>Futuretask间接的继承了Runnable接口，与Runnable不同的是，他有返回值</p>
</blockquote>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">FutureTask</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">></span></span> futureTask <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FutureTask</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Callable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">&#123;</span>
        log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"running========="</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token number">100</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token class-name">Thread</span> thread <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span>futureTask<span class="token punctuation">)</span><span class="token punctuation">;</span>
thread<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
    log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"&#123;&#125;"</span><span class="token punctuation">,</span>
            futureTask<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">ExecutionException</span> e<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span>
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<hr>
<h3 id="2-2-线程运行原理"><a href="#2-2-线程运行原理" class="headerlink" title="2.2 线程运行原理"></a>2.2 线程运行原理</h3><h4 id="栈与栈帧"><a href="#栈与栈帧" class="headerlink" title="栈与栈帧"></a>栈与栈帧</h4><p><img src="https://s1.ax1x.com/2020/10/29/BGW1mt.png"></p>
<ul>
<li>每个线程只能有一个活动栈帧，对应着当前的那个方法</li>
</ul>
<blockquote>
<p>栈帧的相关内容参考JVM</p>
</blockquote>
<h4 id="线程的上下文切换"><a href="#线程的上下文切换" class="headerlink" title="线程的上下文切换"></a>线程的上下文切换</h4><blockquote>
<p>以下会导致线程上下文切换的原因：</p>
</blockquote>
<ul>
<li>线程的cpu时间片用完</li>
<li>垃圾回收</li>
<li>有更高优先级的线程运行</li>
<li>线程自己调用了 sleep yield  wait  join  park  synchronized  lock 等方法</li>
</ul>
<p>当Context Switch发生时，需要由操作系统保存当前线程的状态，并恢复另一个线程的状态，Java中对应的概念就是程序计数器，</p>
<ul>
<li>状态包括，程序计数器，虚拟机栈中的每个栈帧的信息</li>
<li>Context Switch频繁操作可能会影响性能</li>
</ul>
<h3 id="2-3-常见方法"><a href="#2-3-常见方法" class="headerlink" title="2.3 常见方法"></a>2.3 常见方法</h3><blockquote>
<p>参考jdk api 文档</p>
</blockquote>
<h4 id="sleep"><a href="#sleep" class="headerlink" title="sleep"></a>sleep</h4><ul>
<li><p>调用sleep会使得当前线程从running状态变成time waiting状态</p>
</li>
<li><p>其他线程可以使用interrupt方法打断正在睡眠的线程，此时sleep方法会抛出InterruptedException</p>
</li>
<li><p>睡眠结束后的线程未必比会立刻得到执行</p>
</li>
<li><p>建议使用TimeUnit的sleep代替Thread的sleep来获得更好的可读性</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java">在JUC包中，<span class="token class-name">TimeUnit</span>里边包装了一定的时间，可读性更好<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
</li>
</ul>
<hr>
<h4 id="yield"><a href="#yield" class="headerlink" title="yield"></a>yield</h4><ul>
<li><p>调用yield会让当前线程从Running进入Runnable状态，然后调度执行其他同优先级的线程，<strong>如果这时没有同优先级的线程，那么不能保证让当前线程暂停的效果</strong></p>
</li>
<li><p>具体的是西安依赖于操作系统的任务调度器</p>
</li>
</ul>
<hr>
<h4 id="线程优先级"><a href="#线程优先级" class="headerlink" title="线程优先级"></a>线程优先级</h4><ul>
<li>线程优先级会提示调度器优先调度该线程，但它仅仅是一个提示，调度器可以忽略它</li>
<li>如果CPU比较忙，那么优先级高的线程会获得更多的时间片，但CPU闲时，优先级几乎没作用</li>
</ul>
<hr>
<h4 id="join"><a href="#join" class="headerlink" title="join"></a>join</h4><blockquote>
<p>谁调用join，就等待谁结束</p>
</blockquote>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">Thread</span> thread <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
    a <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">,</span><span class="token string">"t1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
thread<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
thread<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p><img src="https://s1.ax1x.com/2020/10/29/BJPAFf.png"></p>
<h4 id="interrupt方法详解"><a href="#interrupt方法详解" class="headerlink" title="interrupt方法详解"></a>interrupt方法详解</h4><h5 id="打断sleep、wait、join的线程"><a href="#打断sleep、wait、join的线程" class="headerlink" title="打断sleep、wait、join的线程"></a>打断sleep、wait、join的线程</h5><p>打断sleep的线程，会清空打断状态，以sleep为例</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">test1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">&#123;</span>
 <span class="token class-name">Thread</span> t1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
 <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span><span class="token punctuation">,</span> <span class="token string">"t1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 t1<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">0.5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 t1<span class="token punctuation">.</span><span class="token function">interrupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">" 打断状态: &#123;&#125;"</span><span class="token punctuation">,</span> t1<span class="token punctuation">.</span><span class="token function">isInterrupted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h5 id="打断正常运行的线程"><a href="#打断正常运行的线程" class="headerlink" title="打断正常运行的线程"></a>打断正常运行的线程</h5><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">test2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">&#123;</span>
 <span class="token class-name">Thread</span> t2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
 <span class="token keyword">while</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 <span class="token class-name">Thread</span> current <span class="token operator">=</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">boolean</span> interrupted <span class="token operator">=</span> current<span class="token punctuation">.</span><span class="token function">isInterrupted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">if</span><span class="token punctuation">(</span>interrupted<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">" 打断状态: &#123;&#125;"</span><span class="token punctuation">,</span> interrupted<span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">break</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>
 <span class="token punctuation">&#125;</span>
 <span class="token punctuation">&#125;</span><span class="token punctuation">,</span> <span class="token string">"t2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 t2<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">0.5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 t2<span class="token punctuation">.</span><span class="token function">interrupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h5 id="打断-park-线程"><a href="#打断-park-线程" class="headerlink" title="打断 park 线程"></a>打断 park 线程</h5><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">test3</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">&#123;</span>
 <span class="token class-name">Thread</span> t1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token punctuation">&#123;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"park..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token class-name">LockSupport</span><span class="token punctuation">.</span><span class="token function">park</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"unpark..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"打断状态：&#123;&#125;"</span><span class="token punctuation">,</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isInterrupted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span><span class="token punctuation">,</span> <span class="token string">"t1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 t1<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">0.5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 t1<span class="token punctuation">.</span><span class="token function">interrupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p><strong>如果打断标记已经是true，则park会失效</strong></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">Thread</span> thread <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
    log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"park----"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">LockSupport</span><span class="token punctuation">.</span><span class="token function">park</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"unpark---"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"打断状态：&#123;&#125;"</span><span class="token punctuation">,</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isInterrupted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token class-name">LockSupport</span><span class="token punctuation">.</span><span class="token function">park</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">/////////这里会立即停止</span>
    log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"unpark---"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token punctuation">&#125;</span><span class="token punctuation">,</span><span class="token string">"t1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
thread<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
thread<span class="token punctuation">.</span><span class="token function">interrupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h4 id="两阶段终止模式"><a href="#两阶段终止模式" class="headerlink" title="两阶段终止模式"></a>两阶段终止模式</h4><blockquote>
<p>在线程T1中如何“优雅”终止线程T2？这里的【优雅】指的是给T2一个料理后事的机会？</p>
</blockquote>
<p><img src="https://s1.ax1x.com/2020/10/29/BJI44x.png"></p>
<h3 id="2-4-主线程与守护线程"><a href="#2-4-主线程与守护线程" class="headerlink" title="2.4 主线程与守护线程"></a>2.4 主线程与守护线程</h3><blockquote>
<p>守护线程，<strong>只要其它非守护线程运行结束了，即使守护线程的代码没有执行完，也会强制结束</strong></p>
</blockquote>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">Thread</span> t1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
    <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isInterrupted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>
    <span class="token comment">// 如果守护线程正常结束，才会执行</span>
    log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"结束"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">,</span><span class="token string">"t1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
t1<span class="token punctuation">.</span><span class="token function">setDaemon</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
t1<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">2000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"main结束"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<ul>
<li>垃圾回收器线程是一种守护线程</li>
<li>Tomcat中的Acceptor和Poller线程都是守护线程，所以Tomcat接收到shutdown命令后，不会等待他们处理完当前请求</li>
</ul>
<h3 id="2-5-线程状态"><a href="#2-5-线程状态" class="headerlink" title="2.5 线程状态"></a>2.5 线程状态</h3><blockquote>
<p>在操作系统层面</p>
</blockquote>
<p><img src="https://s1.ax1x.com/2020/10/30/BYNFC6.png"></p>
<ul>
<li>【初始状态】仅仅是在语言层面创建了线程对象，还未与操作系统线程关联</li>
<li>【可运行状态】（就绪状态）指该线程已被创建，可以由cpu调度执行</li>
<li>【运行状态】指获取了CPU时间片运行中的状态<ul>
<li>当CPU时间片用完，会从【运行状态】转换至【可运行状态】，会导致线程的上下文切换</li>
</ul>
</li>
<li>【阻塞状态】<ul>
<li>如果调用了阻塞API，如BIO读写文件，这时该线程实际上不会用到CPU，会导致线程上下文切换，进入【阻塞状态】</li>
<li>等BIO操作完毕，会由操作系统唤醒阻塞的线程，转换至【可运行状态】</li>
</ul>
</li>
<li>【终止状态】表示线程以及执行完毕，生命周期已经结束，不会再转换为其他状态</li>
</ul>
<blockquote>
<p>在java层面</p>
</blockquote>
<p><img src="https://s1.ax1x.com/2020/10/30/BYUUyD.png"></p>
<h3 id="2-6-小结"><a href="#2-6-小结" class="headerlink" title="2.6 小结"></a>2.6 小结</h3><ul>
<li><p>线程的创建</p>
</li>
<li><p>线程的重要api</p>
</li>
<li><p>线程的状态</p>
</li>
<li><p><strong>应用方面</strong></p>
<ul>
<li>异步调用：主线程执行期间，其他线程异步执行耗时操作</li>
<li>提高效率：并行计算，缩短运行时间</li>
<li>同步等待：join</li>
<li>统筹规划：合理使用线程，得到最优结果</li>
</ul>
</li>
<li><p><strong>原理方面</strong></p>
<ul>
<li>线程运行流程：栈、栈帧、上下文切换、程序计数器</li>
<li>Thread两种创建方式的源码</li>
</ul>
</li>
<li><p><strong>模式方面</strong></p>
<ul>
<li>两阶段终止模式</li>
</ul>
</li>
</ul>
<h2 id="3-共享模型之管程"><a href="#3-共享模型之管程" class="headerlink" title="3. 共享模型之管程"></a>3. 共享模型之管程</h2><h3 id="3-1-共享带来的问题"><a href="#3-1-共享带来的问题" class="headerlink" title="3.1 共享带来的问题"></a>3.1 共享带来的问题</h3><p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201031134251.png"></p>
<h4 id="临界区"><a href="#临界区" class="headerlink" title="临界区"></a>临界区</h4><ul>
<li>一个程序运行多个ianc本身是没有问题的</li>
<li>问题出现在多个线程访问<strong>共享资源</strong>，在多个线程对<strong>共享资源</strong>的读写操作发生了指令交错，就会出现问题</li>
<li>一段代码内如果存在对<strong>共享资源</strong>的多线程读写操作，称这块代码为 <strong>临界区</strong></li>
</ul>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">int</span> counter <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

<span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">increment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
    <span class="token comment">// 临界区</span>
    counter<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span>

<span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">decrement</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
    <span class="token comment">// 临界区</span>
    counter<span class="token operator">--</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h4 id="竞态条件-Race-Condition"><a href="#竞态条件-Race-Condition" class="headerlink" title="竞态条件 Race Condition"></a>竞态条件 Race Condition</h4><h3 id="3-2-synchronized解决方案"><a href="#3-2-synchronized解决方案" class="headerlink" title="3.2 synchronized解决方案"></a>3.2 synchronized解决方案</h3><blockquote>
<p>俗称“对象锁”，采用互斥的方式让同一时刻只有一个线程能够持有【对象锁】，其他线程再想获取这个【对象锁】就会阻塞。不用担心上下文切换</p>
</blockquote>
<p><strong>注意</strong></p>
<p>虽然java中，互斥和同步都能采用synchronized关键字完成，但是他们有本质区别：</p>
<ul>
<li>互斥是保证临界区的竞态条件发生，同一时刻只能有一个线程执行临界区代码</li>
<li>同步是由于线程执行的先后、顺序不同、需要一个线程等待其他线程运行到某个点</li>
</ul>
<h4 id="synchronized"><a href="#synchronized" class="headerlink" title="synchronized"></a>synchronized</h4><p><strong>语法</strong></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">synchronized</span> <span class="token punctuation">(</span>对象<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
    <span class="token comment">// 临界区</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>
<p><strong>思考</strong></p>
<p>synchronized实际是用<strong>对象锁</strong>保证了 <strong>临界区内代码的原子性</strong>，临界区内的代码对外是不可分割的，不会被线程切换所打断。</p>
<p><strong>问题</strong></p>
<blockquote>
<p>如果把synchronized(obj)放在for循环的外面，如何理解？</p>
</blockquote>
<p>原子性</p>
<blockquote>
<p>如果t1 synchronized(obj1) 而 t2 synchronized(obj2) 会怎样运作？</p>
</blockquote>
<p>锁对象要一致，不然没用</p>
<blockquote>
<p>如果t1 synchronized(obj)而t2没有加会怎么样？如何理解？</p>
</blockquote>
<p>t2没有加，当执行它的代码片的时候，它并不会去获取锁对象，而是直接执行代码</p>
<h4 id="方法上的synchronized"><a href="#方法上的synchronized" class="headerlink" title="方法上的synchronized"></a>方法上的synchronized</h4><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">static</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">decrement</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
    <span class="token comment">// 临界区</span>
    counter<span class="token operator">--</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>
<blockquote>
<p>这里看似加在方法上，其实锁住的是调用它的对象</p>
</blockquote>
<h4 id="线程八锁"><a href="#线程八锁" class="headerlink" title="线程八锁"></a>线程八锁</h4><p>情况1：<u>立刻出现1和2，或者立刻出现2和1</u></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java">    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">Number</span> n1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
            log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"begin"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            n1<span class="token punctuation">.</span><span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
            log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"begin"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            n1<span class="token punctuation">.</span><span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>

<span class="token annotation punctuation">@Slf4j</span><span class="token punctuation">(</span>topic <span class="token operator">=</span> <span class="token string">"c.Number"</span><span class="token punctuation">)</span>
<span class="token keyword">class</span> <span class="token class-name">Number</span><span class="token punctuation">&#123;</span>
    <span class="token keyword">public</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token keyword">public</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>情况2：<u>1s后出现1 2或者2 1s后出现1</u></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java">   <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">Number</span> n1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
            log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"begin"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            n1<span class="token punctuation">.</span><span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
            log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"begin"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            n1<span class="token punctuation">.</span><span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

<span class="token annotation punctuation">@Slf4j</span><span class="token punctuation">(</span>topic <span class="token operator">=</span> <span class="token string">"c.Number"</span><span class="token punctuation">)</span>
<span class="token keyword">class</span> <span class="token class-name">Number</span><span class="token punctuation">&#123;</span>
    <span class="token keyword">public</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        <span class="token class-name">ThreadUtil</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">///让线程1睡眠1s</span>

        log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token keyword">public</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>情况3：<u>3 2 1s后1，3 1s后 1 2 ，2 3 1s后1</u></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java">    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">Number</span> n1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
            log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"begin"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            n1<span class="token punctuation">.</span><span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
            log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"begin"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            n1<span class="token punctuation">.</span><span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
            log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"begin"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            n1<span class="token punctuation">.</span><span class="token function">c</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

<span class="token annotation punctuation">@Slf4j</span><span class="token punctuation">(</span>topic <span class="token operator">=</span> <span class="token string">"c.Number"</span><span class="token punctuation">)</span>
<span class="token keyword">class</span> <span class="token class-name">Number</span><span class="token punctuation">&#123;</span>
    <span class="token keyword">public</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        <span class="token class-name">ThreadUtil</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token keyword">public</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">c</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"3"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>情况4：<u>1 2，2 1</u></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Slf4j</span><span class="token punctuation">(</span>topic <span class="token operator">=</span> <span class="token string">"c.Number"</span><span class="token punctuation">)</span>
<span class="token keyword">class</span> <span class="token class-name">Number</span><span class="token punctuation">&#123;</span>
 <span class="token keyword">public</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>
 <span class="token keyword">public</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 <span class="token class-name">Number</span> n1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token class-name">Number</span> n2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span> n1<span class="token punctuation">.</span><span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span> n2<span class="token punctuation">.</span><span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>情况5：2 1s 后 1</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Slf4j</span><span class="token punctuation">(</span>topic <span class="token operator">=</span> <span class="token string">"c.Number"</span><span class="token punctuation">)</span>
<span class="token keyword">class</span> <span class="token class-name">Number</span><span class="token punctuation">&#123;</span>
 <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>
 <span class="token keyword">public</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>北京市昌平区建材城西路金燕龙办公楼一层 电话：<span class="token number">400</span><span class="token operator">-</span><span class="token number">618</span><span class="token operator">-</span><span class="token number">9090</span>
<span class="token punctuation">&#125;</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 <span class="token class-name">Number</span> n1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span> n1<span class="token punctuation">.</span><span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span> n1<span class="token punctuation">.</span><span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>情况6：1s 后12， 或 2 1s后 1</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Slf4j</span><span class="token punctuation">(</span>topic <span class="token operator">=</span> <span class="token string">"c.Number"</span><span class="token punctuation">)</span>
<span class="token keyword">class</span> <span class="token class-name">Number</span><span class="token punctuation">&#123;</span>
 <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>
 <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 <span class="token class-name">Number</span> n1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span> n1<span class="token punctuation">.</span><span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span> n1<span class="token punctuation">.</span><span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>情况7：2 1s 后 1</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Slf4j</span><span class="token punctuation">(</span>topic <span class="token operator">=</span> <span class="token string">"c.Number"</span><span class="token punctuation">)</span>
<span class="token keyword">class</span> <span class="token class-name">Number</span><span class="token punctuation">&#123;</span>
 <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>
 <span class="token keyword">public</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 <span class="token class-name">Number</span> n1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token class-name">Number</span> n2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span> n1<span class="token punctuation">.</span><span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span> n2<span class="token punctuation">.</span><span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>情况8：1s 后12， 或 2 1s后 1</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Slf4j</span><span class="token punctuation">(</span>topic <span class="token operator">=</span> <span class="token string">"c.Number"</span><span class="token punctuation">)</span>
<span class="token keyword">class</span> <span class="token class-name">Number</span><span class="token punctuation">&#123;</span>
 <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>
 <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> <span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 <span class="token class-name">Number</span> n1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token class-name">Number</span> n2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span> n1<span class="token punctuation">.</span><span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span> n2<span class="token punctuation">.</span><span class="token function">b</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="3-3-变量的线程安全分析"><a href="#3-3-变量的线程安全分析" class="headerlink" title="3.3 变量的线程安全分析"></a>3.3 变量的线程安全分析</h3><blockquote>
<p><strong>成员变量和静态变量是否线程安全？</strong></p>
</blockquote>
<ul>
<li>如果他们没有共享，则线程安全</li>
<li>如果他们被共享了，根据他们的状态是否能够改变，又分为：<ul>
<li>如果是只读操作，则线程安全</li>
<li>如果是读写操作，则这段代码是临界区，需要考虑线程安全问题</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>局部变量是否线程安全？</strong></p>
</blockquote>
<ul>
<li>局部变量是线程安全的</li>
<li>局部变量引用的对象未必是安全的：<ul>
<li>如果该对象没有逃离方法的作用访问，它是线程安全的</li>
<li>如果该对象逃离方法的作用范围，则需要考虑线程安全</li>
</ul>
</li>
</ul>
<h3 id="3-4-常见的线程安全类"><a href="#3-4-常见的线程安全类" class="headerlink" title="3.4 常见的线程安全类"></a>3.4 常见的线程安全类</h3><ul>
<li>String</li>
<li>Integer</li>
<li>StringBuffer</li>
<li>Random</li>
<li>Vector</li>
<li>HashTable</li>
<li>JUC包下的类</li>
</ul>
<blockquote>
<p>这里说他们的线程安全是指，多个线程调用他们<strong>同一个实例的某个方法时</strong>，是线程安全的</p>
</blockquote>
<h3 id="3-5Monitor-监视器"><a href="#3-5Monitor-监视器" class="headerlink" title="3.5Monitor 监视器"></a>3.5Monitor 监视器</h3><blockquote>
<p><strong>对象头</strong></p>
</blockquote>
<p>普通对象</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201031193830.png"></p>
<p>数组对象</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201031193901.png"></p>
<p>Mark Word的结构为</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201031193942.png"></p>
<p>64位虚拟机Mark Word</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201031194046.png"></p>
<h4 id="Monitor原理"><a href="#Monitor原理" class="headerlink" title="Monitor原理"></a>Monitor原理</h4><p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201103174042.png" alt="监视器工作原理"></p>
<ul>
<li>刚开始Monitor中的Owner为null</li>
<li>当Thread-2执行synchronized(obj)就会将Monitor的所有者Owner置为Thread-2，Monitor中只能有一个Owner</li>
<li>当Thread-2上锁的过程中，如果Thread-3，Thread-4，Thread-5也来执行synchronized(obj)，就会进入EntryList中，进入阻塞状态</li>
<li>当Thread-2执行完同步代码块中的内容，然后唤醒EntryList中的等待线程来竞争锁，<strong>竞争锁的过程是非公平的</strong></li>
<li>WAITING中的线程是：之前获得过锁，但条件又不满足进入WAITING状态的线程</li>
</ul>
<hr>
<h3 id="3-6-轻量级锁"><a href="#3-6-轻量级锁" class="headerlink" title="3.6 轻量级锁"></a>3.6 轻量级锁</h3><blockquote>
<p>如果一个对象虽然有多个线程访问，但多线程访问的时间是错开的（<strong>没有竞争</strong>），那么可以使用轻量级锁来优化</p>
<p>轻量级锁对使用者是透明的，语法仍然是synchronized</p>
</blockquote>
<p>假设有两个方法同步代码块， 利用同一个对象加锁</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">static</span>  <span class="token keyword">final</span> <span class="token class-name">Object</span> obj <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Object</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">method1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
    <span class="token keyword">synchronized</span> <span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        <span class="token comment">// 同步块A</span>
        <span class="token function">method2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>

<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">method2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">synchronized</span> <span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        <span class="token comment">// 同步块B</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<ul>
<li><p>创建锁记录对象，每个线程的栈帧中都会包含一个锁记录的结构，内存可以存储锁定对象的Mark Word</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201103213042.png"></p>
</li>
<li><p>让锁记录中Object reference指向锁对象，并尝试用CAS替换Object的Mark Word，将Mark Word的值存入锁记录中</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201103213844.png"></p>
</li>
<li><p>如果CAS替换成功，<strong>对象头中存储了所记录地址和状态00</strong>，表示由该线程给对象加锁，这时如下图示：</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201103214200.png"></p>
</li>
<li><p>如果CAS失败：</p>
<ul>
<li><p>如果是其他线程已经持有了该对象的轻量级锁，这是表明有竞争，进入锁膨胀过程</p>
</li>
<li><p>如果是自己执行了synchronized锁重入，那么再添加一条Lock Record作为重入的计数</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201103214743.png" alt="synchronized 锁重入！存入null"></p>
</li>
<li><p>当退出synchronized代码块，进行解锁，如果有取值为null的锁记录，表示有重入，这时充值锁记录，表示重入计数减一</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201103214200.png"></p>
</li>
<li><p>当推出synchronized代码块，进行解锁，如果锁记录的值不为null，这时用cas将Mark Word的值恢复给对象头</p>
<ul>
<li>成功：解锁成功</li>
<li>失败：说明轻量级锁进行了锁膨胀或者已经升级为重量级锁，进入重量级锁解锁流程</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="3-7-锁膨胀"><a href="#3-7-锁膨胀" class="headerlink" title="3.7 锁膨胀"></a>3.7 锁膨胀</h3><blockquote>
<p>如果再尝试加轻量级锁的过程中，CAS操作无法成功，这时一种情况就是有其他线程为此对象加上了轻量级锁（有竞争），这时就需要进行锁膨胀，将轻量级锁变为重量级锁。</p>
</blockquote>
<ul>
<li><p>当Thread-1进行轻量级加锁时，Thread-0已经对该对象加了轻量级锁</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201103220659.png"></p>
</li>
<li><p>这时Thread-1加轻量级锁失败，进入锁膨胀流程</p>
<ul>
<li>即为Object对象申请Monitor锁，让Object指向重量级锁地址</li>
<li>然后自己进入Monitor的EntryList BLOCKED</li>
</ul>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201104104249.png"></p>
</li>
<li><p>当Thread-0退出同步块解锁时，使用cas将Mark Word的值恢复给对象头，失败。这时会进入重量级解锁流程，即按照Monitor地址找到Monitor对象，设置Owner为null，唤醒EntryList中的BLOCKED线程</p>
</li>
</ul>
<hr>
<h3 id="3-8-自旋"><a href="#3-8-自旋" class="headerlink" title="3.8 自旋"></a>3.8 自旋</h3><blockquote>
<p>对于自旋有好多不同的版本，有的说是在轻量级锁的时候自旋，有的说是在重量级锁的时候自旋？？？？？</p>
</blockquote>
<p><strong>重量级锁竞争的时候</strong>，使用自旋来进行优化，如果当前线程自旋成功（这时候持锁线程已经推出了同步块，释放了锁），这时当前线程就可以避免阻塞。</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201104144726.png" alt="自旋成功"></p>
<p>自旋失败会进入entryList中，进入BLOCKED状态</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201104144859.png" alt="自旋失败"></p>
<p><strong>补充</strong></p>
<ul>
<li>java6以后自旋锁是自适应的，比如对象杠杆的一次自旋操作成功过，那么认为这次自旋成功的可能性会高，就多自旋几次；反之就少自旋甚至不自旋，智能控制。</li>
<li>自旋会占用cpu时间，多核cpu才能发挥优势</li>
<li>java7之后不能控制是否开启自旋功能</li>
</ul>
<h3 id="3-9-偏向锁"><a href="#3-9-偏向锁" class="headerlink" title="3.9 偏向锁"></a>3.9 偏向锁</h3><blockquote>
<p>当轻量级锁在没有竞争的时候，每次重入仍然需要进行一次CAS，相当浪费啊</p>
<p>所以java6中引入了偏向锁来进行进一步优化：只有第一次CAS<strong>将线程ID设置到对象头的Mark Word中</strong>，之后发现这个线程ID是自己的就表示没有竞争，不用重新CAS。以后只要不发生竞争，这个对象就归该线程所有。</p>
</blockquote>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201104162409.png"></p>
<h4 id="偏向状态"><a href="#偏向状态" class="headerlink" title="偏向状态"></a>偏向状态</h4><p>一个对象创建时：</p>
<ul>
<li>如果开启了偏向锁（默认开启），那么对象创建后，Mark Word值为0x05即最后3位为101，这时它的thread、epoch、age都为0</li>
<li>偏向锁是默认是延迟的，不会在程序启动立即生效，如果想避免延迟，可以加VM参数 <code>-XX:BiasedLockingStrartupDelay=0</code>来禁用延迟</li>
<li>如果没有开启偏向锁，那么对象创建后，Mark Word值为0x01 即最后3位为001，这时它的hash code、age都为0，第一次用到hash code时才会赋值 <strong>并且，算出hash code以后，偏向锁就会失效，因为放不下了,当一个对象当前正处于偏向锁状态，并且需要计算其identity hash code的话，则它的偏向锁会被撤销，并且锁会膨胀为重量级锁</strong></li>
</ul>
<h4 id="撤销-调用对象hashCode"><a href="#撤销-调用对象hashCode" class="headerlink" title="撤销-调用对象hashCode"></a>撤销-调用对象hashCode</h4><blockquote>
<p>调用了对象的hashCode，但偏向锁的对象Mark Word中存储的时线程id，如果调用hash Code会导致偏向锁被撤销</p>
</blockquote>
<ul>
<li>轻量级锁会在锁记录中记录hash Code</li>
<li>重量级锁会在Monitor中记录hash Code</li>
</ul>
<p>调用hash Code后使用偏向锁，记得去掉 <code>-XX:-UserBiasedLocking</code></p>
<h4 id="撤销-其他线程使用对象"><a href="#撤销-其他线程使用对象" class="headerlink" title="撤销-其他线程使用对象"></a>撤销-其他线程使用对象</h4><blockquote>
<p>当有其他线程使用偏向锁的时候，会升级为轻量级锁</p>
</blockquote>
<h4 id="撤销-调用wait-notify"><a href="#撤销-调用wait-notify" class="headerlink" title="撤销-调用wait/notify"></a>撤销-调用wait/notify</h4><h4 id="批量重偏向"><a href="#批量重偏向" class="headerlink" title="批量重偏向"></a>批量重偏向</h4><blockquote>
<p>如果对象虽然被多个线程访问，但没有竞争，这时偏向了线程T1的对象仍有机会重新偏向T2，重偏向会重置对象的Thread ID</p>
<p>当撤销偏向锁阈值超过20次后，JVM会给这些对象加锁时重新偏向至加锁线程</p>
</blockquote>
<h4 id="批量撤销"><a href="#批量撤销" class="headerlink" title="批量撤销"></a>批量撤销</h4><blockquote>
<p>当撤销偏向锁阈值超过40次，jvm会把整个类的所有对象都变为不可偏向的，新创建的对象也是不可偏向的。</p>
</blockquote>
<h3 id="3-10-锁消除"><a href="#3-10-锁消除" class="headerlink" title="3.10 锁消除"></a>3.10 锁消除</h3><p>xxx</p>
<h3 id="3-11-锁粗化"><a href="#3-11-锁粗化" class="headerlink" title="3.11 锁粗化"></a>3.11 锁粗化</h3><h2 id="4-wait-notify"><a href="#4-wait-notify" class="headerlink" title="4. wait notify"></a>4. wait notify</h2><blockquote>
<p>原理</p>
</blockquote>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201104212224.png"></p>
<ul>
<li>Owner线程发现条件不满足，调用wait方法，即可进入WaitSet变为WAITING状态</li>
<li>BLOCKED和WAITING的线程都处于阻塞状态，不占用CPU时间片段</li>
<li>BLOCKED线程会在OWner线程释放锁时唤醒</li>
<li>WAITING线程追在Owner线程调用notify或notifyAll时唤醒，但唤醒后并不意味着立刻获得锁，仍需进入EntryList重新竞争</li>
</ul>
<h3 id="API介绍"><a href="#API介绍" class="headerlink" title="API介绍"></a>API介绍</h3><ul>
<li>obj.wait()让进入object近十期的线程到waitSet等待</li>
<li>obj.notify()在object上正在waitSet等待的线程中挑一个唤醒</li>
<li>obj.notifyAll()让object上正在waitSet等待的线程全部唤醒</li>
</ul>
<p><strong>调用这些方法必须获取这个对象的锁才能调用</strong> </p>
<h3 id="使用方式"><a href="#使用方式" class="headerlink" title="使用方式"></a>使用方式</h3><blockquote>
<p><strong>sleep(long n)**和</strong>wait(long n)**的区别</p>
</blockquote>
<p>1）sleep是Thread方法，wait是Object方法</p>
<p>2）sleep不需要强制和synchronized配合使用，但wait需要和synchronized一起使用</p>
<p>3）<strong>sleep在睡眠的同时，不会释放对象锁的</strong>，但<strong>wait在等待的时候会释放对象锁</strong></p>
<p>4）他们的状态都是WAITING</p>
<p><strong>规范写法</strong></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// 等待</span>
<span class="token keyword">synchronized</span> <span class="token punctuation">(</span>对象<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
    <span class="token keyword">while</span> <span class="token punctuation">(</span>条件不成立<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        lock<span class="token punctuation">.</span><span class="token function">wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">// do other things</span>
<span class="token punctuation">&#125;</span>

<span class="token comment">// 唤醒</span>
<span class="token keyword">synchronized</span> <span class="token punctuation">(</span>对象<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
    lock<span class="token punctuation">.</span><span class="token function">notifyAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>


<h3 id="模式——保护性暂停"><a href="#模式——保护性暂停" class="headerlink" title="模式——保护性暂停"></a>模式——保护性暂停</h3><blockquote>
<p>用于一个线程等待另一个线程的执行结果</p>
</blockquote>
<p>要点：</p>
<ul>
<li>有一个结果需要从一个线程传递到另一个线程，让他们关联同一个GuardedObject</li>
<li>如果有结果不断从一个线程到另一个线程，那么可以使用<strong>消息队列</strong></li>
<li>jdk中，join实现、Future的实现，采用的就是此模式</li>
<li>因为要等待另一方的结果，因此归类到<strong>同步模式</strong></li>
</ul>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201105190354.png"></p>
<h3 id="模式——生产者消费者模式"><a href="#模式——生产者消费者模式" class="headerlink" title="模式——生产者消费者模式"></a>模式——生产者消费者模式</h3><blockquote>
<p>生产者负责产生结果数据，不关心数据如何处理</p>
<p>消费者专心处理结果数据</p>
<p>消息队列是由容量限制的，满时不会再加入数据，空时不会再消耗数据</p>
<p>jdk中各种阻塞队列，采用的就是这种模式</p>
</blockquote>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201105202048.png"></p>
<p><strong>参考代码</strong></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>study<span class="token punctuation">.</span>n8</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span>extern<span class="token punctuation">.</span>slf4j<span class="token punctuation">.</span></span><span class="token class-name">Slf4j</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">LinkedList</span><span class="token punctuation">;</span>

<span class="token comment">/**
 * @author: Zhang Haoyu
 * @date: 2020/11/5 20:28
 * @description:
 */</span>
<span class="token annotation punctuation">@Slf4j</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">&#123;</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">MessageQueue</span> queue <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MessageQueue</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">3</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            <span class="token keyword">int</span> id <span class="token operator">=</span> i<span class="token punctuation">;</span>
            <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
                queue<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Message</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span><span class="token string">"值"</span><span class="token operator">+</span>id<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span><span class="token punctuation">,</span><span class="token string">"生产者"</span><span class="token operator">+</span>i<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>

        <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
            <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
                <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
                    <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token class-name">Message</span> take <span class="token operator">=</span> queue<span class="token punctuation">.</span><span class="token function">take</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"消费消息"</span><span class="token operator">+</span>take<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                    e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span>
            <span class="token punctuation">&#125;</span>
        <span class="token punctuation">&#125;</span><span class="token punctuation">,</span><span class="token string">"消费者"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

<span class="token punctuation">&#125;</span>
<span class="token annotation punctuation">@Slf4j</span>
<span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">Message</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> id<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> value<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">return</span> <span class="token string">"Message&#123;"</span> <span class="token operator">+</span>
                <span class="token string">"id="</span> <span class="token operator">+</span> id <span class="token operator">+</span>
                <span class="token string">", value='"</span> <span class="token operator">+</span> value <span class="token operator">+</span> <span class="token string">'\''</span> <span class="token operator">+</span>
                <span class="token string">'&#125;'</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">return</span> value<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">return</span> id<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token keyword">public</span> <span class="token class-name">Message</span><span class="token punctuation">(</span><span class="token keyword">int</span> id<span class="token punctuation">,</span> <span class="token class-name">String</span> value<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>id <span class="token operator">=</span> id<span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> value<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>
<span class="token annotation punctuation">@Slf4j</span>
<span class="token keyword">class</span> <span class="token class-name">MessageQueue</span> <span class="token punctuation">&#123;</span>

    <span class="token keyword">private</span> <span class="token class-name">LinkedList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Message</span><span class="token punctuation">></span></span> list <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">LinkedList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">private</span> <span class="token keyword">int</span> capcity<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">MessageQueue</span><span class="token punctuation">(</span><span class="token keyword">int</span> capcity<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>capcity <span class="token operator">=</span> capcity<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">// 取出消息</span>
    <span class="token keyword">public</span> <span class="token class-name">Message</span> <span class="token function">take</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">synchronized</span> <span class="token punctuation">(</span>list<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>

            <span class="token keyword">while</span> <span class="token punctuation">(</span>list<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
                    log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"队列为空"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    list<span class="token punctuation">.</span><span class="token function">wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                    e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span>
            <span class="token punctuation">&#125;</span>

            <span class="token comment">// 从队列头部取</span>
            <span class="token class-name">Message</span> message <span class="token operator">=</span> list<span class="token punctuation">.</span><span class="token function">removeFirst</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"已经消费消息"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            list<span class="token punctuation">.</span><span class="token function">notifyAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span> message<span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>
    <span class="token comment">// 存入消息</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">put</span><span class="token punctuation">(</span><span class="token class-name">Message</span> message<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">synchronized</span> <span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
            <span class="token keyword">while</span> <span class="token punctuation">(</span>list<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">==</span>capcity<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>

                <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
                    log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"队列已满"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    list<span class="token punctuation">.</span><span class="token function">wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                    e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span>

            <span class="token punctuation">&#125;</span>

            list<span class="token punctuation">.</span><span class="token function">addLast</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 唤醒</span>
            log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"已经生产消息"</span><span class="token operator">+</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
            list<span class="token punctuation">.</span><span class="token function">notifyAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<blockquote>
<p>20:46:56.977 [生产者1] DEBUG com.study.n8.MessageQueue - 已经生产消息Message{id=1, value=’值1’}<br>20:46:56.979 [生产者0] DEBUG com.study.n8.MessageQueue - 已经生产消息Message{id=0, value=’值0’}<br>20:46:56.979 [生产者2] DEBUG com.study.n8.MessageQueue - 队列已满<br>20:46:57.976 [消费者] DEBUG com.study.n8.MessageQueue - 已经消费消息<br>20:46:57.976 [消费者] DEBUG com.study.n8.Test - 消费消息Message{id=1, value=’值1’}<br>20:46:57.976 [生产者2] DEBUG com.study.n8.MessageQueue - 已经生产消息Message{id=2, value=’值2’}<br>20:46:58.976 [消费者] DEBUG com.study.n8.MessageQueue - 已经消费消息<br>20:46:58.976 [消费者] DEBUG com.study.n8.Test - 消费消息Message{id=0, value=’值0’}<br>20:46:59.977 [消费者] DEBUG com.study.n8.MessageQueue - 已经消费消息<br>20:46:59.977 [消费者] DEBUG com.study.n8.Test - 消费消息Message{id=2, value=’值2’}<br>20:47:00.977 [消费者] DEBUG com.study.n8.MessageQueue - 队列为空</p>
</blockquote>
<h2 id="5-Park和Unpark"><a href="#5-Park和Unpark" class="headerlink" title="5.Park和Unpark"></a>5.Park和Unpark</h2><p><strong>基本使用</strong></p>
<blockquote>
<p>是属于LockSupport类中的方法</p>
</blockquote>
<p>暂停当前线程：<code>LockSupport.park()</code></p>
<p>恢复某个线程的运行：<code>LockSupport.unpark(暂停线程对象)</code></p>
<p><strong>特点比较</strong></p>
<ul>
<li>wait和notifyAll必须配合Object Monitor一起使用，而unpark不必</li>
<li>park&amp;unpark是以线程为单位来阻塞和唤醒线程的，相对于wait和notifyAll，这个更加精确</li>
<li>park&amp;unpark可以先unpark，而wait&amp;notify不能先notify</li>
</ul>
<p><strong>原理</strong></p>
<blockquote>
<p>每个线程都有一个Parker对象，由三部分组成：<strong>mutex</strong>、<strong>cond</strong>、<strong>counter</strong></p>
</blockquote>
<h2 id="线程状态转换"><a href="#线程状态转换" class="headerlink" title="线程状态转换"></a>线程状态转换</h2><p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201105210741.png"></p>
<ol>
<li><p>NEW—RUNNABLE</p>
<p><code>start()</code></p>
</li>
<li><p>RUNNABLE—WAITING</p>
<blockquote>
<ul>
<li>线程使用synchronized获取对象锁后，<ul>
<li>调用wait()方法进入WAITING状态</li>
<li>调用notify()或者notifyAll()或者interrupt()方法时<ul>
<li>竞争锁成功，进入RUNNABLE状态</li>
<li>竞争锁失败，进入BLOCKED状态</li>
</ul>
</li>
</ul>
</li>
</ul>
</blockquote>
</li>
<li><p>RUNNABLE—WAITING</p>
<blockquote>
<p>当前线程调用<code>t.join()</code>，当前线程从RUNNABLE—&gt;WAITING</p>
<ul>
<li>当前线程在t线程对象的监视器上等待</li>
<li>t线程运行结束，或调用了当前线程的interrupt()时，当前线程从WAITING—&gt;RUNNABLE</li>
</ul>
</blockquote>
</li>
<li><p>RUNNABLE—WAITING</p>
<blockquote>
<ul>
<li>当前线程调用 LockSupport.park() 方法会让当前线程从RUNNABLE–&gt;WAITING</li>
<li>调用LockSupport.unpark(目标线程)或者调用了interrupt()，会让目标线程从WAITING—&gt;RUNNABLE</li>
</ul>
</blockquote>
</li>
<li><p>RUNNABLE—TIMED_WAITING</p>
<blockquote>
<p>线程使用synchronized获取对象锁后</p>
<ul>
<li>调用 <code>t.wait(long n)</code>。t线程从RUNNABLE–&gt;TIMED_WAITING</li>
<li>t线程等待时间超过了n毫秒，或者调用了notify()，notifyAll()，interrupt()时<ul>
<li>竞争锁成功，t线程从TIMED_WAITING —&gt;RUNNABLE</li>
<li>竞争锁失败，t线程从TIMED_WAITING —&gt;BLOCKED</li>
</ul>
</li>
</ul>
</blockquote>
</li>
<li><p>RUNNABLE—TIMED_WAITING</p>
<blockquote>
<ul>
<li>当前线程调用了t.join(n)方法，当前线程会进入TIMED_WAITING状态<ul>
<li>注意是 <strong>当前线程</strong>在<strong>t线程对象的监视器</strong>上的等待</li>
</ul>
</li>
<li><strong>当前线程</strong>等待时间超过n毫秒，或者t线程运行结束，或者调用了当前线程的interrupt()时，<strong>当前线程</strong>会从TIMED_WAITING —&gt;RUNNABLE</li>
</ul>
</blockquote>
</li>
<li><p>RUNNABLE—TIMED_WAITING</p>
<blockquote>
<ul>
<li>当前线程调用Thread.sleep(long n)，当前线程会进入TIMED_WAITING状态</li>
<li>当前线程等待时间超过了n毫秒，当前线程从TIMED_WAITING —&gt;RUNNABLE</li>
</ul>
</blockquote>
</li>
<li><p>RUNNABLE — TIMED_WAITING</p>
<blockquote>
<p>当前线程调用了 LockSupport.parkNanos(long nanos)或者LockSupport.parkUntil(long millis)时，当前线程从RUNNABLE　—&gt;TIMED_WAITING</p>
<p> 调用LockSupport.unpark(目标线程)或者调用了线程的interrupt()，或者等待超时，会让目标线程从TIMED_WAITING状态进入RUNNABLE状态</p>
</blockquote>
</li>
<li><p>RUNNABLE — BLOCKED</p>
<blockquote>
<ul>
<li><strong>线程</strong>用synchronized获取对象锁如果竞争失败，会进入entryList中，进入BLOCKED状态</li>
<li>持有obj锁线程的同步代码块执行完毕，会唤醒该对象上所有BLOCKED的线程重新竞争，如果其中t线程竞争成功，会从BLOCKED状态变为RUNNABLE，其他失败的仍然会是BLOCKED状态</li>
</ul>
</blockquote>
</li>
<li><p>RUNNABLE — TERMINATED</p>
<blockquote>
<p>当线程的所有代码运行完毕，会进入TERMINATED状态</p>
</blockquote>
</li>
</ol>
<h2 id="6-ReentrantLock"><a href="#6-ReentrantLock" class="headerlink" title="6. ReentrantLock"></a>6. ReentrantLock</h2><blockquote>
<p>相对于synchronized它具备的特点是:</p>
<ul>
<li>可中断</li>
<li>可以设置超时时间</li>
<li>可以设置为公平锁</li>
<li>支持多个条件变量</li>
</ul>
<p>与synchronized一样支持可重入</p>
</blockquote>
<p>基本语法</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">ReentrantLock</span> reentrantLock <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ReentrantLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 加锁</span>
reentrantLock<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">// 临界区</span>

<span class="token punctuation">&#125;</span><span class="token keyword">finally</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">// 释放锁</span>
    reentrantLock<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="可重入"><a href="#可重入" class="headerlink" title="可重入"></a>可重入</h3><blockquote>
<p>可重入是指同一个线程如果首次获得了这把锁，那么因为它是这把锁的拥有者，因此有权利再次获取这把锁，如果是不可重入锁，那么第二次获得锁时，自己也会被锁挡住</p>
</blockquote>
<h3 id="可打断"><a href="#可打断" class="headerlink" title="可打断"></a>可打断</h3><blockquote>
<p>在等待锁的过程中，其他线程可以使用interrupt()来打断，<strong>使用<code>lock.inteeruptibly()</code>为可打断，，原先的<code>lock.lock()</code>为不可打断</strong></p>
</blockquote>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">ReentrantLock</span> lock <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ReentrantLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Thread</span> t1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token punctuation">&#123;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"启动..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
 lock<span class="token punctuation">.</span><span class="token function">lockInterruptibly</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">//尝试获得锁</span>
 <span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> <span class="token comment">// 如果被打断会抛异常，进而退出</span>
 e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"等锁的过程中被打断"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">return</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>
 <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"获得了锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span> <span class="token keyword">finally</span> <span class="token punctuation">&#123;</span>
 lock<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">,</span> <span class="token string">"t1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
lock<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">//先用主线程获得锁</span>
log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"获得了锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
t1<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 启动t1线程，这时候t1获得不了所</span>
<span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
 <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 t1<span class="token punctuation">.</span><span class="token function">interrupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 主线程中打断t1线程</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"执行打断"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span> <span class="token keyword">finally</span> <span class="token punctuation">&#123;</span>
 lock<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="锁超时"><a href="#锁超时" class="headerlink" title="锁超时"></a>锁超时</h3><blockquote>
<p>使用 <code>tryLock()</code> 方法来尝试获得锁</p>
</blockquote>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">ReentrantLock</span> lock <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ReentrantLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Thread</span> t1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token punctuation">&#123;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"启动..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>lock<span class="token punctuation">.</span><span class="token function">tryLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"获取立刻失败，返回"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token keyword">return</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>
 <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
 log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"获得了锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span> <span class="token keyword">finally</span> <span class="token punctuation">&#123;</span>
 lock<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">,</span> <span class="token string">"t1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
lock<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"获得了锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">Thread</span> t1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
    log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"尝试获取锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
        <span class="token comment">// 定义等待最多1秒，如果还是获取不到，就结束，，该方法可以被打断</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>lock<span class="token punctuation">.</span><span class="token function">tryLock</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span>SECONDS<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"获取不到锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> <span class="token comment">// 其他线程调用interrupt方法打断</span>
        e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
    <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
        log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"获取到锁了"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span><span class="token keyword">finally</span> <span class="token punctuation">&#123;</span>
        lock<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">,</span><span class="token string">"t1"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
t1<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="公平锁"><a href="#公平锁" class="headerlink" title="公平锁"></a>公平锁</h3><blockquote>
<p>默认是不公平的锁，通过构造方法可以控制</p>
</blockquote>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201107155721.png"></p>
<p>更容易先进先得，但是没必要，<strong>会降低并发度</strong></p>
<h3 id="条件变量"><a href="#条件变量" class="headerlink" title="条件变量"></a>条件变量</h3><blockquote>
<p>synchronized中也有条件变量，就是当 条件不满足的时候，会进入waitSet等待</p>
<p>ReentrantLock的条件变量强大之处在于<strong>它支持多个条件变量</strong></p>
</blockquote>
<p><strong>使用流程</strong></p>
<ul>
<li>await 前需要获得锁</li>
<li>await执行后，会释放锁，进入conditionObject等待</li>
<li>await的线程被唤醒（或打断，或超时）去重新竞争lock锁</li>
<li>竞争lock锁成功后，从await后继续执行</li>
</ul>
<h3 id="模式——顺序控制"><a href="#模式——顺序控制" class="headerlink" title="模式——顺序控制"></a>模式——顺序控制</h3><p><strong>固定运行顺序</strong></p>
<p>synchronized+wait+notify（notifyAll）</p>
<p>ReentrantLock+condition+await+signal（signalAll）</p>
<p>LockSupport+park+unpark</p>
<h2 id="7-共享模型之内存"><a href="#7-共享模型之内存" class="headerlink" title="7. 共享模型之内存"></a>7. 共享模型之内存</h2><blockquote>
<p>共享变量在多线程间的【可见性】问题与多条指令执行时的【有序性】问题</p>
</blockquote>
<h3 id="java内存模型"><a href="#java内存模型" class="headerlink" title="java内存模型"></a>java内存模型</h3><blockquote>
<p>JMM即（java memory model），它定义了主存，工作内存抽象概念，底层对应着CPU寄存器，缓存，硬件内存，CPU指令优化等</p>
</blockquote>
<p>JMM体现在以下几个方面</p>
<ul>
<li>原子性==保证指令不会受到线程上下文切换的影响</li>
<li>可见性==保证指令不会受CPU缓存的影响</li>
<li>有序性==保证指令不会受CPU指令并行优化的影响</li>
</ul>
<h3 id="可见性"><a href="#可见性" class="headerlink" title="可见性"></a>可见性</h3><p><strong>退不出去的循环</strong></p>
<p>先来看一个现象，main 线程对 run 变量的修改对于 t 线程不可见，导致了 t 线程无法停止：</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">static</span> <span class="token keyword">boolean</span> run <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">&#123;</span>
 <span class="token class-name">Thread</span> t <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
 <span class="token keyword">while</span><span class="token punctuation">(</span>run<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
 <span class="token comment">// ....</span>
 <span class="token punctuation">&#125;</span>
 <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 t<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 run <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token comment">// 线程t不会如预想的停下来</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<ul>
<li><p>初始状态下，t线程刚开始从主内存中读取了run的值到工作内存</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201107204134.png"></p>
</li>
<li><p>因为 t 线程要频繁从主内存中读取 run 的值，<strong>JIT 编译器会将 run 的值缓存至自己工作内存中的高速缓存中，减少对主存中 run 的访问，提高效率</strong></p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201107204229.png"></p>
</li>
<li><p>1 秒之后，main 线程修改了 run 的值，并同步至主存，<strong>而 t 是从自己工作内存中的高速缓存中读取这个变量</strong></p>
<p><strong>的值</strong>，结果永远是旧值</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201107204324.png"></p>
</li>
</ul>
<p><strong>解决办法：volatile关键字</strong></p>
<blockquote>
<p>它可以用来修饰成员变量和静态成员变量，他可以<strong>避免线程从自己的工作缓存中查找变量的值，必须到主存中获取它的值</strong>，线程操作 volatile 变量都是直接操作主存</p>
</blockquote>
<hr>
<h3 id="可见性-vs-原子性"><a href="#可见性-vs-原子性" class="headerlink" title="可见性 vs 原子性"></a>可见性 vs 原子性</h3><blockquote>
<p>一个线程对volatile变量的修改对另一个线程可见，但是不能保证原子性，<strong>仅用在一个写线程，多个读线程的情况下</strong></p>
</blockquote>
<p>所以用volatile去处理原子性问题是不正确的！！！！</p>
<p><strong>注意的一点：</strong></p>
<p>synchronized 既可以保证原子性，又可以保证可见性，但是缺点是synchronized属于重量级操作，性能相对更低。</p>
<hr>
<h3 id="模式——两阶段终止模式"><a href="#模式——两阶段终止模式" class="headerlink" title="模式——两阶段终止模式"></a>模式——两阶段终止模式</h3><blockquote>
<p>用volatile 重写这个模式</p>
</blockquote>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * TODO: 更改两阶段终止模式===volatile
 *          
 * @author Zhang Hao yu
 * @date 2020/11/8 14:32
 */</span>
<span class="token annotation punctuation">@Slf4j</span><span class="token punctuation">(</span>topic <span class="token operator">=</span> <span class="token string">"c.TwoPhaseTermination"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">TwoPhaseTermination</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">/**监控线程*/</span>
    <span class="token keyword">private</span> <span class="token class-name">Thread</span> monitorThread<span class="token punctuation">;</span>
    <span class="token comment">/**用于控制线程继续工作*/</span>
    <span class="token keyword">volatile</span> <span class="token keyword">private</span> <span class="token keyword">boolean</span> stop <span class="token operator">=</span><span class="token boolean">false</span><span class="token punctuation">;</span>

    <span class="token comment">/** TODO: 停止监控线程
     * @author ZhangHaoyu
     * @return void
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">stop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        <span class="token comment">// 设置停止标记为真</span>
        stop <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
        monitorThread<span class="token punctuation">.</span><span class="token function">interrupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
    <span class="token comment">/** TODO: 启动监控线程
     * @author ZhangHaoyu
     * @return void
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>

        monitorThread <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
            <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
                <span class="token class-name">Thread</span> current <span class="token operator">=</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>stop<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
                    log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"执行关闭资源等操作"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token keyword">break</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span>

                <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
                    <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"执行监控记录"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                    log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"打断线程执行的操作"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span>
            <span class="token punctuation">&#125;</span>
        <span class="token punctuation">&#125;</span><span class="token punctuation">,</span><span class="token string">"monitor"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        monitorThread<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p><strong>缺点</strong></p>
<p>当多个线程或本线程同时做了start操作的时候，会创建多个线程，这很浪费，我们只需要一个就够了。</p>
<hr>
<h3 id="模式——Balking（犹豫）"><a href="#模式——Balking（犹豫）" class="headerlink" title="模式——Balking（犹豫）"></a>模式——Balking（犹豫）</h3><blockquote>
<p>犹豫模式在一个线程发现另一个线程或本地线程做了某一件相同的事情，那么本地线程就无需再做了，直接结束返回</p>
</blockquote>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>study<span class="token punctuation">.</span>n9</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span>extern<span class="token punctuation">.</span>slf4j<span class="token punctuation">.</span></span><span class="token class-name">Slf4j</span><span class="token punctuation">;</span>

<span class="token comment">/**
 * TODO: 更改两阶段终止模式===volatile
 *
 * @author Zhang Hao yu
 * @date 2020/11/8 14:32
 */</span>
<span class="token annotation punctuation">@Slf4j</span><span class="token punctuation">(</span>topic <span class="token operator">=</span> <span class="token string">"c.TwoPhaseTermination"</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">TwoPhaseTermination</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">/**监控线程*/</span>
    <span class="token keyword">private</span> <span class="token class-name">Thread</span> monitorThread<span class="token punctuation">;</span>
    <span class="token comment">/**用于控制线程继续工作*/</span>
    <span class="token keyword">volatile</span> <span class="token keyword">private</span> <span class="token keyword">boolean</span> stop <span class="token operator">=</span><span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token comment">/**犹豫模式：判断是否执行过start方法，如果执行过，就不让他再次执行了*/</span>
    <span class="token keyword">private</span> <span class="token keyword">volatile</span> <span class="token keyword">boolean</span> starting <span class="token operator">=</span><span class="token boolean">false</span><span class="token punctuation">;</span>

    <span class="token comment">/** TODO: 停止监控线程
     * @author ZhangHaoyu
     * @return void
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">stop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        <span class="token comment">// 设置停止标记为真</span>
        stop <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
        monitorThread<span class="token punctuation">.</span><span class="token function">interrupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
    <span class="token comment">/** TODO: 启动监控线程
     * @author ZhangHaoyu
     * @return void
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        <span class="token comment">/*
         这里用双重if来减少线程获取锁的频率
         */</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>starting<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
        <span class="token keyword">synchronized</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>starting<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
                <span class="token keyword">return</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span>
            <span class="token comment">// 设置启动标记为正在执行</span>
            starting <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>

        monitorThread <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">&#123;</span>
            <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
                <span class="token class-name">Thread</span> current <span class="token operator">=</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>stop<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
                    log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"执行关闭资源等操作"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    starting <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
                    <span class="token keyword">break</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span>

                <span class="token keyword">try</span> <span class="token punctuation">&#123;</span>
                    <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"执行监控记录"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                    log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">"打断线程执行的操作"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">&#125;</span>
            <span class="token punctuation">&#125;</span>
        <span class="token punctuation">&#125;</span><span class="token punctuation">,</span><span class="token string">"monitor"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        monitorThread<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>在这里我们通过犹豫模式，可以解决这类问题。</p>
<hr>
<p><strong>应用场景</strong></p>
<p>一般我们把这个模式运用在web环境下，当前端发过来多个请求，tomcat就需要去线程池中使用线程去处理，我们就需要考虑到synchronized的问题了。当前端页面多次点击按钮调用 start 时，应该判断监控线程是否已经启动。</p>
<p>它还经常用来实现线程安全的单例</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">Singleton</span> <span class="token punctuation">&#123;</span>
     <span class="token keyword">private</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
     <span class="token punctuation">&#125;</span>
     <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">Singleton</span> INSTANCE <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
     <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">synchronized</span> <span class="token class-name">Singleton</span> <span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
     <span class="token keyword">if</span> <span class="token punctuation">(</span>INSTANCE <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
     <span class="token keyword">return</span> INSTANCE<span class="token punctuation">;</span>
     <span class="token punctuation">&#125;</span>
 
     INSTANCE <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token keyword">return</span> INSTANCE<span class="token punctuation">;</span>
     <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p><strong>对比保护性暂停模式</strong>：保护性暂停模式用在一个线程等待另一个线程的执行结果，当条件不满足时线程等待。</p>
<hr>
<h3 id="有序性"><a href="#有序性" class="headerlink" title="有序性"></a>有序性</h3><blockquote>
<p>JVM会在不影响正确性的前提下，调整语句的执行顺序</p>
</blockquote>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">static</span> <span class="token keyword">int</span> i<span class="token punctuation">;</span>
<span class="token keyword">static</span> <span class="token keyword">int</span> j<span class="token punctuation">;</span>
i <span class="token operator">=</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">;</span>
j <span class="token operator">=</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">;</span>

可以是先给 i 赋值，再给 j 赋值
    也可以是先给 j 赋值，再给 i 赋值；<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>i和j的赋值操作顺序，对于单线程来说，对最终的结果是不会产生影响的，这种特性就叫做【<strong>指令重排</strong>】</p>
<blockquote>
<p>为何要这么做？指令重排的优化</p>
</blockquote>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201108155042.png" alt="参考黑马的例子"></p>
<p><strong>优化</strong></p>
<p>事实上，现代处理器会设计为一个时钟周期完成一条执行时间最长的 CPU 指令。为什么这么做呢？可以想到指令还可以再划分成一个个更小的阶段，例如，每条指令都可以分为： <strong>取指令</strong> - <strong>指令译码</strong> - <strong>执行指令</strong> - <strong>内存访问</strong> - <strong>数据写回</strong> 这 5 个阶段</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201108155248.png"></p>
<blockquote>
<p><strong>术语参考：</strong></p>
<ul>
<li>instruction fetch (IF)</li>
<li>instruction decode (ID)</li>
<li>execute (EX)</li>
<li>memory access (MEM)</li>
<li>register write back (WB)</li>
</ul>
</blockquote>
<p>在不改变程序结果的前提下，这些指令的各个阶段可以通过<strong>重排序</strong>和<strong>组合</strong>来实现<strong>指令级并行</strong>，这一技术在 80年代中叶到 90年代中叶占据了计算架构的重要地位。</p>
<blockquote>
<p>提示：</p>
<p>分阶段，分工是提升效率的关键！</p>
</blockquote>
<p>指令重排的前提就是<strong>重排的指令不影响结果</strong></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// 可以重排的例子</span>
<span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span> <span class="token comment">// 指令1</span>
<span class="token keyword">int</span> b <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span> <span class="token comment">// 指令2</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span> a <span class="token operator">+</span> b <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 不能重排的例子</span>
<span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span> <span class="token comment">// 指令1</span>
<span class="token keyword">int</span> b <span class="token operator">=</span> a <span class="token operator">-</span> <span class="token number">5</span><span class="token punctuation">;</span> <span class="token comment">// 指令2</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<hr>
<h4 id="一种情况"><a href="#一种情况" class="headerlink" title="一种情况"></a>一种情况</h4><p><strong>诡异的结果</strong></p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">int</span> num <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">boolean</span> ready <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token comment">// 线程1 执行此方法</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">actor1</span><span class="token punctuation">(</span><span class="token class-name">I_Result</span> r<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 <span class="token keyword">if</span><span class="token punctuation">(</span>ready<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
 r<span class="token punctuation">.</span>r1 <span class="token operator">=</span> num <span class="token operator">+</span> num<span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
 r<span class="token punctuation">.</span>r1 <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
 <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>
<span class="token comment">// 线程2 执行此方法</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">actor2</span><span class="token punctuation">(</span><span class="token class-name">I_Result</span> r<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> 
 num <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span>
 ready <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> 
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>I_Result 是一个对象，有一个属性 r1 用来保存结果，问，可能的结果有几种？</p>
<p>有同学这么分析</p>
<p>情况1：线程1 先执行，这时 ready = false，所以进入 else 分支结果为 1</p>
<p>情况2：线程2 先执行 num = 2，但没来得及执行 ready = true，线程1 执行，还是进入 else 分支，结果为1</p>
<p>情况3：线程2 执行到 ready = true，线程1 执行，这回进入 if 分支，结果为 4（因为 num 已经执行过了）</p>
<p><strong>情况4</strong>：结果还有可能是 0 ！！！！！！！！</p>
<p>这种情况下是：线程2 执行 ready = true，切换到线程1，进入 if 分支，相加为 0，再切回线程2 执行 num = 2</p>
<p><strong>这种现象就叫做指令重排</strong>，是 JIT 编译器在运行时的一些优化，这个现象需要通过大量测试才能复现。</p>
<blockquote>
<p>解决办法：</p>
<p>在ready变量前加上volatile关键字</p>
<p><strong>因为volatile 可以防止在他之前的代码被指令重排！</strong></p>
</blockquote>
<hr>
<h3 id="volatile-原理"><a href="#volatile-原理" class="headerlink" title="volatile 原理"></a>volatile 原理</h3><p>volatile的底层实现原理是内存屏障，Memory Barrier（Memory Fence）</p>
<ul>
<li>对volatile变量的写指令后会加入<strong>写屏障</strong></li>
<li>对volatile变量的读指令前会加入<strong>读屏障</strong></li>
</ul>
<h4 id="如何保证可见性？"><a href="#如何保证可见性？" class="headerlink" title="如何保证可见性？"></a>如何保证可见性？</h4><ul>
<li><p>写屏障【sfence】保证<strong>在该屏障之前的，对共享变量的改动，都同步到主存当中</strong></p>
</li>
<li><pre><code class="java">public void actor2(I_Result r) &#123;
 num = 2;
 ready = true; // ready 是 volatile 赋值带写屏障
 // 写屏障
&#125;
<pre class="line-numbers language-none"><code class="language-none">
- 读屏障【lfence】保证**在该屏障之后，对共享变量的读取，加载的是主存中最新数据**

- &#96;&#96;&#96;java
  public void actor1(I_Result r) &#123;
   &#x2F;&#x2F; 读屏障
   &#x2F;&#x2F; ready 是 volatile 读取值带读屏障
   if(ready) &#123;
   r.r1 &#x3D; num + num;
   &#125; else &#123;
   r.r1 &#x3D; 1;
   &#125;
  &#125;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
![](https://gitee.com/zhang_hao_yu123/images/raw/master/20201108162528.png)
</code></pre>
</li>
</ul>
<hr>
<h4 id="如何保证有序性？"><a href="#如何保证有序性？" class="headerlink" title="如何保证有序性？"></a>如何保证有序性？</h4><ul>
<li>写屏障会确保指令重排序时，不会将写屏障之前的代码排在写屏障之后</li>
<li>读屏障会确保指令重排序时，不会将读屏障之后的代码排在读屏障之前</li>
</ul>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201108165137.png"></p>
<blockquote>
<p>不能解决指令的交错，<strong>即不能保证原子性</strong></p>
</blockquote>
<ul>
<li>写屏障仅仅保证之后的读操作能够读到最新的结果，但不能保证读操作在写屏障之前</li>
<li>有序性的保证也只是保证了本线程内相关代码不被重排序</li>
</ul>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201108165342.png"></p>
<p>t2线程读取操作发生在t1线程写入主存之前，这样就证明了不能保证原子性</p>
<hr>
<h4 id="dcl问题（double-checked-locking）"><a href="#dcl问题（double-checked-locking）" class="headerlink" title="dcl问题（double-checked locking）"></a>dcl问题（double-checked locking）</h4><p>以著名的 double-checked locking 单例模式为例</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">Singleton</span> <span class="token punctuation">&#123;</span>
     <span class="token keyword">private</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> <span class="token punctuation">&#125;</span>
     <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">Singleton</span> INSTANCE <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
     <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">Singleton</span> <span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> 
         <span class="token keyword">if</span><span class="token punctuation">(</span>INSTANCE <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> <span class="token comment">// t2</span>
         	<span class="token comment">// 首次访问会同步，而之后的使用没有 synchronized</span>
                 <span class="token keyword">synchronized</span><span class="token punctuation">(</span><span class="token class-name">Singleton</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                     <span class="token keyword">if</span> <span class="token punctuation">(</span>INSTANCE <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> <span class="token comment">// t1</span>
                     	INSTANCE <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                     <span class="token punctuation">&#125;</span> 
             <span class="token punctuation">&#125;</span>
         <span class="token punctuation">&#125;</span>
         <span class="token keyword">return</span> INSTANCE<span class="token punctuation">;</span>
     <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>特点：</p>
<ul>
<li>懒惰实例化</li>
<li>首次使用getInstance()才使用synchronized加锁，后续使用时无需加锁</li>
<li>有隐含的，但很关键的一点：第一个if使用了INSTANCE变量，但是在同步代码块之外，并且synchronized可以保证可见性，却不能解决指令重排</li>
</ul>
<p>getInstance的字节码：</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token number">0</span><span class="token operator">:</span> getstatic #<span class="token number">2</span> <span class="token comment">// Field INSTANCE:Lcn/itcast/n5/Singleton;</span>
<span class="token number">3</span><span class="token operator">:</span> ifnonnull <span class="token number">37</span>
<span class="token number">6</span><span class="token operator">:</span> ldc #<span class="token number">3</span> <span class="token comment">// class cn/itcast/n5/Singleton</span>
<span class="token number">8</span><span class="token operator">:</span> dup
<span class="token number">9</span><span class="token operator">:</span> astore_0
<span class="token number">10</span><span class="token operator">:</span> monitorenter
<span class="token number">11</span><span class="token operator">:</span> getstatic #<span class="token number">2</span> <span class="token comment">// Field INSTANCE:Lcn/itcast/n5/Singleton;</span>
<span class="token number">14</span><span class="token operator">:</span> ifnonnull <span class="token number">27</span>
<span class="token number">17</span><span class="token operator">:</span> <span class="token keyword">new</span> #<span class="token number">3</span> <span class="token comment">// class cn/itcast/n5/Singleton</span>
<span class="token number">20</span><span class="token operator">:</span> dup
<span class="token number">21</span><span class="token operator">:</span> invokespecial #<span class="token number">4</span> <span class="token comment">// Method "&lt;init>":()V</span>
<span class="token number">24</span><span class="token operator">:</span> putstatic #<span class="token number">2</span> <span class="token comment">// Field INSTANCE:Lcn/itcast/n5/Singleton;</span>
<span class="token number">27</span><span class="token operator">:</span> aload_0
<span class="token number">28</span><span class="token operator">:</span> monitorexit
<span class="token number">29</span><span class="token operator">:</span> <span class="token keyword">goto</span> <span class="token number">37</span>
<span class="token number">32</span><span class="token operator">:</span> astore_1
<span class="token number">33</span><span class="token operator">:</span> aload_0
<span class="token number">34</span><span class="token operator">:</span> monitorexit
<span class="token number">35</span><span class="token operator">:</span> aload_1
<span class="token number">36</span><span class="token operator">:</span> athrow
<span class="token number">37</span><span class="token operator">:</span> getstatic #<span class="token number">2</span> <span class="token comment">// Field INSTANCE:Lcn/itcast/n5/Singleton;</span>
<span class="token number">40</span><span class="token operator">:</span> areturn<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>其中：</p>
<ul>
<li>17 表示创建对象，将对象引用入栈   // new Singleton</li>
<li>20 表示复制一份对象引用   // 引用地址</li>
<li>21 表示利用一个对象引用，调用构造方法</li>
<li>24 表示利用一个对象引用，赋值给static INSTANCE</li>
</ul>
<p><strong>也许JVM会优化为，先执行24，再执行21</strong></p>
<p>在多线程的情况下：因为外面也有一个if调用了INSTANCE，所以可能会发生危险！！</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201108174038.png"></p>
<p>关键在于0：getStatic这行代码在synchronized之外，可以越过monitor读取INSTANCE变量的值</p>
<p>这时t1还未完全将构造方法执行完毕，如果在构造方法中要执行很多初始化操作，那么t2拿到的将会是一个未初始化完毕的实例</p>
<p>对INSTANCE使用volatile修饰即可，可以禁用指令重排，但要注意jdk5以上才会有效</p>
<hr>
<h4 id="dcl问题解决"><a href="#dcl问题解决" class="headerlink" title="dcl问题解决"></a>dcl问题解决</h4><blockquote>
<p>在INSTANCE前加上volatile</p>
</blockquote>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// -------------------------------------> 加入对 INSTANCE 变量的读屏障</span>
<span class="token number">0</span><span class="token operator">:</span> getstatic #<span class="token number">2</span> <span class="token comment">// Field INSTANCE:Lcn/itcast/n5/Singleton;</span>
<span class="token number">3</span><span class="token operator">:</span> ifnonnull <span class="token number">37</span>
<span class="token number">6</span><span class="token operator">:</span> ldc #<span class="token number">3</span> <span class="token comment">// class cn/itcast/n5/Singleton</span>
<span class="token number">8</span><span class="token operator">:</span> dup
<span class="token number">9</span><span class="token operator">:</span> astore_0
<span class="token number">10</span><span class="token operator">:</span> monitorenter <span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-></span> 保证原子性、可见性
<span class="token number">11</span><span class="token operator">:</span> getstatic #<span class="token number">2</span> <span class="token comment">// Field INSTANCE:Lcn/itcast/n5/Singleton;</span>
<span class="token number">14</span><span class="token operator">:</span> ifnonnull <span class="token number">27</span>
<span class="token number">17</span><span class="token operator">:</span> <span class="token keyword">new</span> #<span class="token number">3</span> <span class="token comment">// class cn/itcast/n5/Singleton</span>
<span class="token number">20</span><span class="token operator">:</span> dup
<span class="token number">21</span><span class="token operator">:</span> invokespecial #<span class="token number">4</span> <span class="token comment">// Method "&lt;init>":()V</span>
<span class="token number">24</span><span class="token operator">:</span> putstatic #<span class="token number">2</span> <span class="token comment">// Field INSTANCE:Lcn/itcast/n5/Singleton;</span>
<span class="token comment">// -------------------------------------> 加入对 INSTANCE 变量的写屏障</span>
<span class="token number">27</span><span class="token operator">:</span> aload_0
<span class="token number">28</span><span class="token operator">:</span> monitorexit <span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">></span> 保证原子性、可见性
<span class="token number">29</span><span class="token operator">:</span> <span class="token keyword">goto</span> <span class="token number">37</span>
<span class="token number">32</span><span class="token operator">:</span> astore_1
<span class="token number">33</span><span class="token operator">:</span> aload_0
<span class="token number">34</span><span class="token operator">:</span> monitorexit
<span class="token number">35</span><span class="token operator">:</span> aload_1
<span class="token number">36</span><span class="token operator">:</span> athrow
<span class="token number">37</span><span class="token operator">:</span> getstatic #<span class="token number">2</span> <span class="token comment">// Field INSTANCE:Lcn/itcast/n5/Singleton;</span>
<span class="token number">40</span><span class="token operator">:</span> areturn<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>读写volatile变量的时候会加读写屏障，保证下面两点：</p>
<ul>
<li>可见性<ul>
<li>写屏障（sfence）保证在该屏障之前的t1对共享变量的改动，都同步到主存当中</li>
<li>而读屏障（lfence）保证在该屏障之后t2对共享变量的读取，加载的是主存中最新数据</li>
</ul>
</li>
<li>有序性<ul>
<li>写屏障会确保指令重排序时，不会将写屏障之前的代码排在写屏障之后</li>
<li>读屏障会确保指令重排序时，不会将读屏障之后的代码排在读屏障之前</li>
</ul>
</li>
<li>更底层是，读写变量时使用lock指令来控制多核cpu之间的可见性与有序性</li>
</ul>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201108180237.png"></p>
<hr>
<h3 id="happens-before规则"><a href="#happens-before规则" class="headerlink" title="happens-before规则"></a>happens-before规则</h3><p> 规定了 <strong>对共享变量的写操作对其他线程的读操作可见</strong>，它是可见性与有序性的一套规则总结。</p>
<ul>
<li><p>线程m 解锁之前对变量的写，对于接下来获取m锁的其他线程来说应该是读可见</p>
</li>
<li><p>线程对volatile变量的写，对接下来其他线程对该变量的读可见</p>
</li>
<li><p>线程在start之前，对变量的写，对该线程开始后对该变量的读可见</p>
</li>
<li><p>线程结束前对变量的写，对其他线程得知它结束后的读可见（比如其他线程调用 isAlive()或 join()）</p>
</li>
<li><p>线程A打断线程B前，对变量的写，对于其他线程得知B被打断后，对变量的读可见</p>
</li>
<li><p>对变量默认值（0，null，false）的写入，对于其他线程读可见</p>
</li>
<li><p>具有传递性，如果 x hb-&gt;y  y hb-&gt;z 那么 x hb-&gt;z，配合volatile的防指令重排，可以如下图所示</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201109105927.png"></p>
</li>
</ul>
<h3 id="单例模式线程安全问题"><a href="#单例模式线程安全问题" class="headerlink" title="单例模式线程安全问题"></a>单例模式线程安全问题</h3><p>实现1：</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// 问题1：为什么加 final</span>
<span class="token comment">// 问题2：如果实现了序列化接口, 还要做什么来防止反序列化破坏单例</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">Singleton</span> <span class="token keyword">implements</span> <span class="token class-name">Serializable</span> <span class="token punctuation">&#123;</span>
     <span class="token comment">// 问题3：为什么设置为私有? 是否能防止反射创建新的实例?</span>
     <span class="token keyword">private</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span><span class="token punctuation">&#125;</span>
     <span class="token comment">// 问题4：这样初始化是否能保证单例对象创建时的线程安全?</span>
     <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Singleton</span> INSTANCE <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token comment">// 问题5：为什么提供静态方法而不是直接将 INSTANCE 设置为 public, 说出你知道的理由</span>
     <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">Singleton</span> <span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
     	<span class="token keyword">return</span> INSTANCE<span class="token punctuation">;</span>
     <span class="token punctuation">&#125;</span>
     <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">readResolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
     	<span class="token keyword">return</span> INSTANCE<span class="token punctuation">;</span>
     <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>实现2：</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// 问题1：枚举单例是如何限制实例个数的</span>
<span class="token comment">// 问题2：枚举单例在创建时是否有并发问题</span>
<span class="token comment">// 问题3：枚举单例能否被反射破坏单例</span>
<span class="token comment">// 问题4：枚举单例能否被反序列化破坏单例</span>
<span class="token comment">// 问题5：枚举单例属于懒汉式还是饿汉式</span>
<span class="token comment">// 问题6：枚举单例如果希望加入一些单例创建时的初始化逻辑该如何做</span>
<span class="token keyword">enum</span> <span class="token class-name">Singleton</span> <span class="token punctuation">&#123;</span> 
 INSTANCE<span class="token punctuation">;</span> 
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>实现3：</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">Singleton</span> <span class="token punctuation">&#123;</span>
 <span class="token keyword">private</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> <span class="token punctuation">&#125;</span>
 <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">Singleton</span> INSTANCE <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
     <span class="token comment">// 分析这里的线程安全, 并说明有什么缺点</span>
 <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">synchronized</span> <span class="token class-name">Singleton</span> <span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
     <span class="token keyword">if</span><span class="token punctuation">(</span> INSTANCE <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
     	<span class="token keyword">return</span> INSTANCE<span class="token punctuation">;</span>
     <span class="token punctuation">&#125;</span> 
     INSTANCE <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     	<span class="token keyword">return</span> INSTANCE<span class="token punctuation">;</span>
     <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>实现4：</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">Singleton</span> <span class="token punctuation">&#123;</span>
 <span class="token keyword">private</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> <span class="token punctuation">&#125;</span>
 <span class="token comment">// 问题1：解释为什么要加 volatile ?</span>
 <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">volatile</span> <span class="token class-name">Singleton</span> INSTANCE <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
 
 <span class="token comment">// 问题2：对比实现3, 说出这样做的意义 </span>
 <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">Singleton</span> <span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
         <span class="token keyword">if</span> <span class="token punctuation">(</span>INSTANCE <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> 
         	<span class="token keyword">return</span> INSTANCE<span class="token punctuation">;</span>
         <span class="token punctuation">&#125;</span>
         <span class="token keyword">synchronized</span> <span class="token punctuation">(</span><span class="token class-name">Singleton</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> 
         <span class="token comment">// 问题3：为什么还要在这里加为空判断, 之前不是判断过了吗</span>
         <span class="token keyword">if</span> <span class="token punctuation">(</span>INSTANCE <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> <span class="token comment">// t2 </span>
         	<span class="token keyword">return</span> INSTANCE<span class="token punctuation">;</span>
         <span class="token punctuation">&#125;</span>
         INSTANCE <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
         	<span class="token keyword">return</span> INSTANCE<span class="token punctuation">;</span>
         <span class="token punctuation">&#125;</span> 
 	<span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>实现5：</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">Singleton</span> <span class="token punctuation">&#123;</span>
     <span class="token keyword">private</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> <span class="token punctuation">&#125;</span>
     <span class="token comment">// 问题1：属于懒汉式还是饿汉式</span>
     <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">LazyHolder</span> <span class="token punctuation">&#123;</span>
     	<span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Singleton</span> INSTANCE <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token punctuation">&#125;</span>
     <span class="token comment">// 问题2：在创建时是否有并发问题</span>
     <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">Singleton</span> <span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
     	<span class="token keyword">return</span> <span class="token class-name">LazyHolder</span><span class="token punctuation">.</span>INSTANCE<span class="token punctuation">;</span>
     <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>




<h2 id="8-共享模型之无锁"><a href="#8-共享模型之无锁" class="headerlink" title="8. 共享模型之无锁"></a>8. 共享模型之无锁</h2><h3 id="CAS"><a href="#CAS" class="headerlink" title="CAS"></a>CAS</h3><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">withdraw</span><span class="token punctuation">(</span><span class="token class-name">Integer</span> amount<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span> 
    <span class="token keyword">while</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
         <span class="token comment">// 需要不断尝试，直到成功为止</span>
         <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                 <span class="token comment">// 比如拿到了旧值 1000</span>
                 <span class="token keyword">int</span> prev <span class="token operator">=</span> balance<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                 <span class="token comment">// 在这个基础上 1000-10 = 990</span>
                 <span class="token keyword">int</span> next <span class="token operator">=</span> prev <span class="token operator">-</span> amount<span class="token punctuation">;</span>
                 <span class="token comment">/*
                 compareAndSet 正是做这个检查，在 set 前，先比较 prev 与当前值
                 - 不一致了，next 作废，返回 false 表示失败
                 比如，别的线程已经做了减法，当前值已经被减成了 990
                 那么本线程的这次 990 就作废了，进入 while 下次循环重试
                 - 一致，以 next 设置为新值，返回 true 表示成功
                 */</span>
                  <span class="token keyword">if</span> <span class="token punctuation">(</span>balance<span class="token punctuation">.</span><span class="token function">compareAndSet</span><span class="token punctuation">(</span>prev<span class="token punctuation">,</span> next<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
             		<span class="token keyword">break</span><span class="token punctuation">;</span>
             <span class="token punctuation">&#125;</span>
         <span class="token punctuation">&#125;</span>
     <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>其中的关键是 compareAndSet，它的简称就是 CAS （也有 Compare And Swap 的说法），它必须是原子操作。</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201113205128.png"></p>
<blockquote>
<p><strong>注意</strong>  </p>
<ul>
<li><p>其实 CAS 的底层是 lock cmpxchg 指令（X86 架构），在单核 CPU 和多核 CPU 下都能够保证【比较-交换】的原子性。</p>
</li>
<li><p>在多核状态下，某个核执行到带 lock 的指令时，CPU 会让总线锁住，当这个核把此指令执行完毕，再开启总线。这个过程中不会被线程的调度机制所打断，保证了多个线程对内存操作的准确性，是原子的。****</p>
</li>
</ul>
</blockquote>
<hr>
<p><strong>volatile</strong></p>
<p>获取共享变量时，为了保证该变量的可见性，需要使用 volatile 修饰</p>
<p>它可以用来修饰成员变量和静态成员变量，他可以避免线程从自己的工作缓存中查找变量的值，必须到主存中获取它的值，线程操作 volatile 变量都是直接操作主存。即一个线程对 volatile 变量的修改，对另一个线程可见。</p>
<blockquote>
<p><strong>注意</strong></p>
<p>volatile 仅仅保证了共享变量的可见性，让其它线程能够看到最新值，但不能解决指令交错问题（不能保证原子性）</p>
</blockquote>
<p>CAS 必须借助 volatile 才能读取到共享变量的最新值来实现【比较并交换】的效果</p>
<p><strong>为什么无锁效率高</strong></p>
<ul>
<li><p>无锁情况下，即使重试失败，线程始终在高速运行，没有停歇，而 synchronized 会让线程在没有获得锁的时候，发生上下文切换，进入阻塞。打个比喻</p>
</li>
<li><p>线程就好像高速跑道上的赛车，高速运行时，速度超快，一旦发生上下文切换，就好比赛车要减速、熄火，等被唤醒又得重新打火、启动、加速… 恢复到高速运行，代价比较大</p>
</li>
<li><p>但无锁情况下，因为线程要保持运行，需要额外 CPU 的支持，CPU 在这里就好比高速跑道，没有额外的跑道，线程想高速运行也无从谈起，虽然不会进入阻塞，但由于没有分到时间片，仍然会进入可运行状态，还是会导致上下文切换。</p>
</li>
</ul>
<p><strong>CAS</strong> <strong>的特点</strong></p>
<p>结合 CAS 和 volatile 可以实现无锁并发，适用于线程数少、多核 CPU 的场景下。</p>
<ul>
<li><p>CAS 是基于乐观锁的思想：最乐观的估计，不怕别的线程来修改共享变量，就算改了也没关系，我吃亏点再重试呗。</p>
</li>
<li><p>synchronized 是基于悲观锁的思想：最悲观的估计，得防着其它线程来修改共享变量，我上了锁你们都别想改，我改完了解开锁，你们才有机会。</p>
</li>
<li><p>CAS 体现的是无锁并发、无阻塞并发，请仔细体会这两句话的意思</p>
<ul>
<li>因为没有使用 synchronized，所以线程不会陷入阻塞，这是效率提升的因素之一</li>
<li>但如果竞争激烈，可以想到重试必然频繁发生，反而效率会受影响</li>
</ul>
</li>
</ul>
<hr>
<p><strong>原子整数</strong></p>
<p>J.U.C 并发包提供了：</p>
<ul>
<li>AtomicBoolean</li>
<li>AtomicInteger</li>
<li>AtomicLong</li>
</ul>
<hr>
<p><strong>原子引用</strong></p>
<ul>
<li>AtomicReference</li>
<li>AtomicMarkableReference</li>
<li>AtomicStampedReference</li>
</ul>
<hr>
<p><strong>ABA问题及解决</strong></p>
<blockquote>
<p>主线程仅能判断出共享变量的值与最初值 A 是否相同，不能感知到这种从 A 改为 B 又 改回 A 的情况，如果主线程希望：</p>
<p>只要有其它线程【动过了】共享变量，那么自己的 cas 就算失败，这时，仅比较值是不够的，需要再加一个版本号</p>
</blockquote>
<p><em>AtomicStampedReference</em></p>
<p> 可以给原子引用加上版本号，追踪原子引用整个的变化过程，如： A -&gt; B -&gt; A -&gt; C ，通过<strong>AtomicStampedReference</strong>，我们可以知道，引用变量中途被更改了几次。但是有时候，并不关心引用变量更改了几次，只是单纯的关心<strong>是否更改过</strong>，所以就有了<strong>AtomicMarkableReference</strong></p>
<hr>
<p><strong>原子数组</strong></p>
<ul>
<li><p>AtomicIntegerArray</p>
</li>
<li><p>AtomicLongArray</p>
</li>
<li><p>AtomicReferenceArray</p>
</li>
</ul>
<hr>
<p><strong>字段更新器</strong></p>
<ul>
<li><p>AtomicReferenceFieldUpdater // 域 字段</p>
</li>
<li><p>AtomicIntegerFieldUpdater</p>
</li>
<li><p>AtomicLongFieldUpdater</p>
</li>
</ul>
<h3 id="unsafe"><a href="#unsafe" class="headerlink" title="unsafe"></a>unsafe</h3><blockquote>
<p>Unsafe 对象提供了非常底层的，操作内存、线程的方法，Unsafe对象不能直接调用，只能通过反射获得</p>
</blockquote>
<h2 id="共享模型之不可变"><a href="#共享模型之不可变" class="headerlink" title="共享模型之不可变"></a>共享模型之不可变</h2><p><strong>不可变性</strong></p>
<blockquote>
<p>保护性copy机制，参考String</p>
</blockquote>
<p><strong>final</strong></p>
<ul>
<li><p>设置final变量的原理</p>
<blockquote>
<p>在赋值操作(putfield)后加入了写屏障，</p>
<p>写屏障保证了在此之前的变化都同步到主存中，并且在此之前的代码不会重排序到写屏障后面</p>
<p>这样就能保证其他线程读取到它的值时不会出现0的情况</p>
</blockquote>
</li>
<li><p>获取final变量的原理</p>
<blockquote>
<p>BIPUSH 读取其他类中的final变量，会直接复制一份放到当前的栈中，相当于在栈中访问</p>
<p>GETSTATIC 会去别的类中读取他们的final变量，相当于在堆中访问</p>
</blockquote>
</li>
</ul>
<p><strong>享元</strong></p>
<h2 id="线程池"><a href="#线程池" class="headerlink" title="线程池"></a>线程池</h2><h3 id="自定义线程池"><a href="#自定义线程池" class="headerlink" title="自定义线程池"></a>自定义线程池</h3><p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201116171518.png"></p>
<h3 id="ThreadPoolExecutor"><a href="#ThreadPoolExecutor" class="headerlink" title="ThreadPoolExecutor"></a>ThreadPoolExecutor</h3><p><strong>线程池状态</strong></p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201116165735.png"></p>
<p>这些信息存储在一个原子变量ctl中，目的是将线程池状态和线程个数合二为一，这样就可以用一次cas操作进行赋值</p>
<h3 id="创建多少线程合适"><a href="#创建多少线程合适" class="headerlink" title="创建多少线程合适"></a>创建多少线程合适</h3><ul>
<li><p>cpu密集型运算</p>
<blockquote>
<p>cpu核数+1，+1保证当前线程由于页缺失故障（操作系统）或其他原因导致暂停时，额外的这个线程就能顶上去，保证cpu周期不被浪费</p>
</blockquote>
</li>
<li><p>I/O密集型运算</p>
<blockquote>
<p>线程数 = 核数 * 期望CPU利用率 * 总时间（CPU计算时间+等待时间）/CPU计算时间</p>
</blockquote>
</li>
</ul>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201116214358.png"></p>
<h2 id="Tomcat线程池"><a href="#Tomcat线程池" class="headerlink" title="Tomcat线程池"></a>Tomcat线程池</h2><p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201117201639.png"></p>
<h2 id="fork-join"><a href="#fork-join" class="headerlink" title="fork/join"></a>fork/join</h2><blockquote>
<p>分治思想，对任务进行拆分的cpu密集型运算，</p>
</blockquote>
<h2 id="JUC"><a href="#JUC" class="headerlink" title="JUC"></a>JUC</h2><h3 id="AQS原理"><a href="#AQS原理" class="headerlink" title="AQS原理"></a>AQS原理</h3><blockquote>
<p>AbstractQueueSynchronizer，是一个阻塞式锁和相关的同步器工具的框架</p>
</blockquote>
<p>特点：</p>
<ul>
<li><p>用state属性来表示资源的状态（独占式和共享模式），子类需要定义如何维护这个状态，控制如何获取锁和释放锁</p>
<ul>
<li><p><code>getState</code>  获取state装填</p>
</li>
<li><p><code>setState</code>  设置state状态</p>
</li>
<li><p><code>compareAndSetState</code>  乐观锁机制设置state状态</p>
</li>
<li><p>独占模式是只有一个线程能够访问资源，而共享模式可以允许多个线程访问资源</p>
</li>
</ul>
</li>
<li><p>提供了基于FIFO的等待队列，类似于Monitor的EntryList</p>
</li>
<li><p>条件变量来实现的等待、唤醒机制、支持多个条件变量，类似于Monitor的WaitSet</p>
</li>
</ul>
<p>子类主要实现的方法：</p>
<ul>
<li><code>tryAcquire</code></li>
<li><code>tryRelease</code></li>
<li><code>tryAcquireShared</code></li>
<li><code>tryReleaseShared</code></li>
<li><code>isHeldExclusively</code></li>
</ul>
<p><strong>目标</strong></p>
<p>AQS要实现的功能目标</p>
<ul>
<li>阻塞版本获取锁acquire和非阻塞的版本尝试获取锁tryAcquire</li>
<li>获取锁超时机制</li>
<li>通过打断取消机制</li>
<li>独占机制及共享机制</li>
<li>条件不满足时的等待机制</li>
</ul>
<p><strong>设计</strong></p>
<p>AQS的基本思想很简单</p>
<blockquote>
<p>获取锁的逻辑</p>
</blockquote>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">while</span><span class="token punctuation">(</span>state 状态不允许获取<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span>队列中还没有此线程<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        入队并阻塞
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span>
当前线程出队<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<blockquote>
<p>释放锁的逻辑</p>
</blockquote>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">if</span><span class="token punctuation">(</span>state 状态允许了<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
    恢复阻塞的线程<span class="token punctuation">(</span>s<span class="token punctuation">)</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>
<p><strong>要点</strong></p>
<ul>
<li><p><strong>state设计</strong></p>
<ul>
<li>state使用volatile配合cas保证其修改时的原子性</li>
<li>state使用了32bit int来维护同步状态，因为当时使用long在很多平台下测试结果并不理想</li>
</ul>
</li>
<li><p><strong>阻塞恢复设计</strong></p>
<ul>
<li>使用park&amp;unpark来实现线程的暂停和恢复</li>
<li>park &amp;unpark是针对线程的，而不是针对同步器的，因此控制粒度更为精细</li>
<li>park线程还可以用interrupt实现</li>
</ul>
</li>
<li><p><strong>队列设计</strong></p>
<ul>
<li>使用FIFO先入先出队列，并不支持优先级队列</li>
<li>设计时借鉴了CLH队列，它是一种单项无锁队列</li>
</ul>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201119113019.png"></p>
<p>队列中有 head 和 tail 两个指针节点，都用 volatile 修饰配合 cas 使用，每个节点有 state 维护节点状态</p>
<blockquote>
<p>入队伪代码，只需要考虑 tail 赋值的原子性</p>
</blockquote>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">do</span><span class="token punctuation">&#123;</span>
    <span class="token comment">// 原来的tail</span>
    <span class="token class-name">Node</span> prev <span class="token operator">=</span> tail<span class="token punctuation">;</span>
    <span class="token comment">// 用cas在原来的tail的基础上改为node</span>
<span class="token punctuation">&#125;</span><span class="token keyword">while</span><span class="token punctuation">(</span>tail<span class="token punctuation">.</span><span class="token function">compareAndSet</span><span class="token punctuation">(</span>prev<span class="token punctuation">,</span>node<span class="token punctuation">)</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<blockquote>
<p>出队伪代码</p>
</blockquote>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// prev是上一个节点</span>
<span class="token keyword">while</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">Node</span> prev <span class="token operator">=</span> node<span class="token punctuation">.</span>prev<span class="token punctuation">)</span><span class="token punctuation">.</span>state <span class="token operator">!=</span> 唤醒状态<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
    
<span class="token punctuation">&#125;</span>
<span class="token comment">// 设置头节点</span>
head <span class="token operator">=</span> node<span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>CLH 好处：</p>
<ul>
<li><strong>无锁，使用自旋</strong></li>
<li><strong>快速，无阻塞</strong></li>
</ul>
</li>
</ul>
<h3 id="ReentrantLock原理"><a href="#ReentrantLock原理" class="headerlink" title="ReentrantLock原理"></a>ReentrantLock原理</h3><p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201117211318.png"></p>
<h4 id="非公平锁实现原理"><a href="#非公平锁实现原理" class="headerlink" title="非公平锁实现原理"></a>非公平锁实现原理</h4><h5 id="加锁解锁流程"><a href="#加锁解锁流程" class="headerlink" title="加锁解锁流程"></a>加锁解锁流程</h5><p>构造器</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token class-name">ReentrantLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">// 默认是非公平锁，NofairSync继承自AQS</span>
 sync <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">NonfairSync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>
<p>没有竞争时</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201119151112.png"></p>
<p>第一个竞争者出现时</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201119151130.png"></p>
<p>Thread-1执行了以下：</p>
<ol>
<li>CAS尝试把state由0改为1，失败</li>
<li>进入tryAcquire逻辑，此时state已经是1，结果任然是失败</li>
<li>接下来进入addWaiter逻辑，构造Node队列<ol>
<li>每一个node都维护一个waitStatus状态，其中0为默认正常状态</li>
<li>Node的创建是懒惰的</li>
<li>其中第一个Node被称为哑元或者哨兵，用来占位，不关联线程</li>
</ol>
</li>
</ol>
<p><img src="C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201119151652850.png" alt="image-20201119151652850"></p>
<p>当线程进入acquireQueued逻辑</p>
<ol>
<li>acquireQueued会在一个死循环中不断尝试获得锁，失败后进入park阻塞</li>
<li>如果自己是老二（紧挨着head），那么再次tryAcquire尝试获取锁，当然这时state仍为1，失败</li>
<li>进入shouldParkAfterFailedAcquire逻辑，将前驱node，即head的waitStatus改为-1，<strong>意为这个节点有责任唤醒后面的一个节点</strong>，这次返回false</li>
</ol>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201119152344.png"></p>
<ol start="4">
<li>shouldParkAfterFailedAcquire执行完毕回到acquireQueued，再次tryAcquire尝试获取锁，  此时state还是1，失败</li>
<li>当再次进入shouldParkAfterFailedAcquire时，因为它的前驱node的waitStatus已经是-1，这次返回true</li>
<li>当进入parkAndCheckInterrupt，Thread-1 被park了</li>
</ol>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201119152619.png"></p>
<p>再次有多个线程经历上述过程竞争失败，变成这个样子</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201119152636.png"></p>
<p>Thread-0 释放锁，进入 tryRelease 流程，如果成功</p>
<ul>
<li>设置exclusiveOwnerThread为Null</li>
<li>state=0</li>
</ul>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201119152736.png"></p>
<p>当前队列不为 null，并且 head 的 waitStatus = -1，进入 unparkSuccessor 流程</p>
<p>找到队列中离 head 最近的一个 Node（没取消的），unpark 恢复其运行，本例中即为 Thread-1</p>
<p>回到 Thread-1 的 acquireQueued 流程</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201119153103.png"></p>
<p>如果加锁成功（没有竞争），会设置</p>
<ul>
<li>exclusiveOwnerThread为Thread-1，state=1</li>
<li>head指向刚刚Thread-1所在的node，该node清空Thread</li>
<li>原本的head因为从链表断开，<strong>可以被垃圾回收</strong></li>
</ul>
<p>这时候如果由其他线程竞争，（非公平的情况）</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201119153259.png"></p>
<p>如果被thread-4抢先</p>
<ul>
<li>thread被设置为exclusiveOwnerThread，state=1</li>
<li>Thread-1再次进入acquireQueued流程，获取锁失败，重新进入park阻塞</li>
</ul>
<hr>
<h5 id="加锁源码"><a href="#加锁源码" class="headerlink" title="加锁源码"></a>加锁源码</h5><h5 id="解锁源码"><a href="#解锁源码" class="headerlink" title="解锁源码"></a>解锁源码</h5><h4 id="可重入原理"><a href="#可重入原理" class="headerlink" title="可重入原理"></a>可重入原理</h4><h4 id="可打断原理"><a href="#可打断原理" class="headerlink" title="可打断原理"></a>可打断原理</h4><h5 id="不可打断模式"><a href="#不可打断模式" class="headerlink" title="不可打断模式"></a>不可打断模式</h5><h5 id="可打断模式"><a href="#可打断模式" class="headerlink" title="可打断模式"></a>可打断模式</h5><h4 id="公平锁实现原理"><a href="#公平锁实现原理" class="headerlink" title="公平锁实现原理"></a>公平锁实现原理</h4><h4 id="条件变量实现原理"><a href="#条件变量实现原理" class="headerlink" title="条件变量实现原理"></a>条件变量实现原理</h4><blockquote>
<p>每个条件变量其实就对应着一个等待队列，其实现类是 ConditionObject</p>
</blockquote>
<h5 id="await流程"><a href="#await流程" class="headerlink" title="await流程"></a>await流程</h5><p>开始 Thread-0 持有锁，调用 await，进入 ConditionObject 的 addConditionWaiter 流程</p>
<p>创建新的 Node 状态为 -2（Node.CONDITION），关联 Thread-0，加入等待队列尾部</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201119154940.png"></p>
<p>接下来进入 AQS 的 fullyRelease 流程，释放同步器上的锁</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201119155013.png"></p>
<p>unpark AQS 队列中的下一个节点，竞争锁，假设没有其他竞争线程，那么 Thread-1 竞争成功</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/image-20201119155032735.png"></p>
<p>park 阻塞 Thread-0</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/image-20201119155043919.png"></p>
<h5 id="signal流程"><a href="#signal流程" class="headerlink" title="signal流程"></a>signal流程</h5><p>假设 Thread-1 要来唤醒 Thread-0</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201119155129.png"></p>
<p>进入 ConditionObject 的 doSignal 流程，取得等待队列中第一个 Node，即 Thread-0 所在 Node</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/20201119164221.png"></p>
<p>执行 transferForSignal 流程，将该 Node 加入 AQS 队列尾部，将 Thread-0 的 waitStatus 改为 0，Thread-3 的</p>
<p>waitStatus 改为 -1</p>
<p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/image-20201119164420461.png"></p>
<p>Thread-1 释放锁，进入 unlock 流程</p>
<h4 id="读写锁"><a href="#读写锁" class="headerlink" title="读写锁"></a>读写锁</h4><p><strong>ReentrantReadWriteLock</strong></p>
<p>当读操作远远高于写操作时，这时候使用<code>读写锁</code> 让<code>读</code>可以并发，提高性能。 类似于数据库中的 <code>select ...from ... lock in share mode</code></p>
<p>提供一个<code>数据容器类</code>内部分别使用读锁保护数据的<code>read()</code>方法，写锁保护数据的<code>write()</code>方法</p>
<ul>
<li>读锁和读锁之间不会阻塞</li>
<li>读锁和写锁之间会阻塞</li>
<li>写锁和写锁之间会阻塞</li>
</ul>
<h5 id="读写锁原理"><a href="#读写锁原理" class="headerlink" title="读写锁原理"></a>读写锁原理</h5><h5 id="StampedLock"><a href="#StampedLock" class="headerlink" title="StampedLock"></a>StampedLock</h5><h5 id="Semaphore"><a href="#Semaphore" class="headerlink" title="Semaphore"></a>Semaphore</h5><blockquote>
<p>限制同时访问共享资源的线程上限，信号量 </p>
</blockquote>
<h5 id="countdownLatch"><a href="#countdownLatch" class="headerlink" title="countdownLatch"></a>countdownLatch</h5><blockquote>
<p>用来进行线程同步写作，等待所有线程完成倒计时</p>
<p>其中构造函数用来初始化等待计数值，await()用来等待计数归零，countDown()用来让计数减一</p>
</blockquote>
<h4 id="线程安全的集合类"><a href="#线程安全的集合类" class="headerlink" title="线程安全的集合类"></a>线程安全的集合类</h4><p><img src="https://gitee.com/zhang_hao_yu123/images/raw/master/image-20201123111413273.png" alt="image-20201123111413273"></p>
<h2 id="补充"><a href="#补充" class="headerlink" title="补充"></a>补充</h2><blockquote>
<p>处理器如何实现原子操作？</p>
</blockquote>
<ol>
<li><p>使用<strong>总线锁</strong>保证原子性</p>
<p>在多个处理器处理同一块共享变量的时候，使用处理器提供的一个<strong>LOCK#信号</strong>，当一个处理器在总线上输出此信号，<strong>其他处理器的请求将被阻塞住</strong>，那么该处理器可以<strong>独享</strong>该共享内存</p>
</li>
<li><p>使用<strong>缓存锁定</strong>保证原子性</p>
<p>频繁使用内存会缓存在处理器中的L1、L2、L3的高速缓存中，那么原子操作可以直接在处理器内部缓存中执行，不用再声明总线锁。</p>
<p>所谓的“缓存锁定”：<img src="https://gitee.com/zhang_hao_yu123/images/raw/master/image-20201123152344569.png" alt="image-20201123152344569"></p>
</li>
</ol>

                
            </div>
            <hr/>

            

    <div class="reprint" id="reprint-statement">
        
            <div class="reprint__author">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-user">
                        文章作者:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="/about" rel="external nofollow noreferrer">Max</a>
                </span>
            </div>
            <div class="reprint__type">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-link">
                        文章链接:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="https://zhy2021.github.io/2020/10/29/java-bing-fa-bian-cheng-cong-0-dao-n/">https://zhy2021.github.io/2020/10/29/java-bing-fa-bian-cheng-cong-0-dao-n/</a>
                </span>
            </div>
            <div class="reprint__notice">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-copyright">
                        版权声明:
                    </i>
                </span>
                <span class="reprint-info">
                    本博客所有文章除特別声明外，均采用
                    <a href="https://creativecommons.org/licenses/by/4.0/deed.zh" rel="external nofollow noreferrer" target="_blank">CC BY 4.0</a>
                    许可协议。转载请注明来源
                    <a href="/about" target="_blank">Max</a>
                    !
                </span>
            </div>
        
    </div>

    <script async defer>
      document.addEventListener("copy", function (e) {
        let toastHTML = '<span>复制成功，请遵循本文的转载规则</span><button class="btn-flat toast-action" onclick="navToReprintStatement()" style="font-size: smaller">查看</a>';
        M.toast({html: toastHTML})
      });

      function navToReprintStatement() {
        $("html, body").animate({scrollTop: $("#reprint-statement").offset().top - 80}, 800);
      }
    </script>



            <div class="tag_share" style="display: block;">
                <div class="post-meta__tag-list" style="display: inline-block;">
                    
                        <div class="article-tag">
                            
                                <a href="/tags/%E5%B9%B6%E5%8F%91/">
                                    <span class="chip bg-color">并发</span>
                                </a>
                            
                        </div>
                    
                </div>
                <div class="post_share" style="zoom: 80%; width: fit-content; display: inline-block; float: right; margin: -0.15rem 0;">
                    <link rel="stylesheet" type="text/css" href="/libs/share/css/share.min.css">
<div id="article-share">

    
    <div class="social-share" data-sites="twitter,facebook,google,qq,qzone,wechat,weibo,douban,linkedin" data-wechat-qrcode-helper="<p>微信扫一扫即可分享！</p>"></div>
    <script src="/libs/share/js/social-share.min.js"></script>
    

    

</div>

                </div>
            </div>
            
        </div>
    </div>

    

    

    

    

    
        <style>
    .valine-card {
        margin: 1.5rem auto;
    }

    .valine-card .card-content {
        padding: 20px 20px 5px 20px;
    }

    #vcomments textarea {
        box-sizing: border-box;
        background: url("/medias/comment_bg.png") 100% 100% no-repeat;
    }

    #vcomments p {
        margin: 2px 2px 10px;
        font-size: 1.05rem;
        line-height: 1.78rem;
    }

    #vcomments blockquote p {
        text-indent: 0.2rem;
    }

    #vcomments a {
        padding: 0 2px;
        color: #4cbf30;
        font-weight: 500;
        text-decoration: none;
    }

    #vcomments img {
        max-width: 100%;
        height: auto;
        cursor: pointer;
    }

    #vcomments ol li {
        list-style-type: decimal;
    }

    #vcomments ol,
    ul {
        display: block;
        padding-left: 2em;
        word-spacing: 0.05rem;
    }

    #vcomments ul li,
    ol li {
        display: list-item;
        line-height: 1.8rem;
        font-size: 1rem;
    }

    #vcomments ul li {
        list-style-type: disc;
    }

    #vcomments ul ul li {
        list-style-type: circle;
    }

    #vcomments table, th, td {
        padding: 12px 13px;
        border: 1px solid #dfe2e5;
    }

    #vcomments table, th, td {
        border: 0;
    }

    table tr:nth-child(2n), thead {
        background-color: #fafafa;
    }

    #vcomments table th {
        background-color: #f2f2f2;
        min-width: 80px;
    }

    #vcomments table td {
        min-width: 80px;
    }

    #vcomments h1 {
        font-size: 1.85rem;
        font-weight: bold;
        line-height: 2.2rem;
    }

    #vcomments h2 {
        font-size: 1.65rem;
        font-weight: bold;
        line-height: 1.9rem;
    }

    #vcomments h3 {
        font-size: 1.45rem;
        font-weight: bold;
        line-height: 1.7rem;
    }

    #vcomments h4 {
        font-size: 1.25rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    #vcomments h5 {
        font-size: 1.1rem;
        font-weight: bold;
        line-height: 1.4rem;
    }

    #vcomments h6 {
        font-size: 1rem;
        line-height: 1.3rem;
    }

    #vcomments p {
        font-size: 1rem;
        line-height: 1.5rem;
    }

    #vcomments hr {
        margin: 12px 0;
        border: 0;
        border-top: 1px solid #ccc;
    }

    #vcomments blockquote {
        margin: 15px 0;
        border-left: 5px solid #42b983;
        padding: 1rem 0.8rem 0.3rem 0.8rem;
        color: #666;
        background-color: rgba(66, 185, 131, .1);
    }

    #vcomments pre {
        font-family: monospace, monospace;
        padding: 1.2em;
        margin: .5em 0;
        background: #272822;
        overflow: auto;
        border-radius: 0.3em;
        tab-size: 4;
    }

    #vcomments code {
        font-family: monospace, monospace;
        padding: 1px 3px;
        font-size: 0.92rem;
        color: #e96900;
        background-color: #f8f8f8;
        border-radius: 2px;
    }

    #vcomments pre code {
        font-family: monospace, monospace;
        padding: 0;
        color: #e8eaf6;
        background-color: #272822;
    }

    #vcomments pre[class*="language-"] {
        padding: 1.2em;
        margin: .5em 0;
    }

    #vcomments code[class*="language-"],
    pre[class*="language-"] {
        color: #e8eaf6;
    }

    #vcomments [type="checkbox"]:not(:checked), [type="checkbox"]:checked {
        position: inherit;
        margin-left: -1.3rem;
        margin-right: 0.4rem;
        margin-top: -1px;
        vertical-align: middle;
        left: unset;
        visibility: visible;
    }

    #vcomments b,
    strong {
        font-weight: bold;
    }

    #vcomments dfn {
        font-style: italic;
    }

    #vcomments small {
        font-size: 85%;
    }

    #vcomments cite {
        font-style: normal;
    }

    #vcomments mark {
        background-color: #fcf8e3;
        padding: .2em;
    }

    #vcomments table, th, td {
        padding: 12px 13px;
        border: 1px solid #dfe2e5;
    }

    table tr:nth-child(2n), thead {
        background-color: #fafafa;
    }

    #vcomments table th {
        background-color: #f2f2f2;
        min-width: 80px;
    }

    #vcomments table td {
        min-width: 80px;
    }

    #vcomments [type="checkbox"]:not(:checked), [type="checkbox"]:checked {
        position: inherit;
        margin-left: -1.3rem;
        margin-right: 0.4rem;
        margin-top: -1px;
        vertical-align: middle;
        left: unset;
        visibility: visible;
    }
</style>

<div class="card valine-card" data-aos="fade-up">
    <div class="comment_headling" style="font-size: 20px; font-weight: 700; position: relative; padding-left: 20px; top: 15px; padding-bottom: 5px;">
        <i class="fas fa-comments fa-fw" aria-hidden="true"></i>
        <span>评论</span>
    </div>
    <div id="vcomments" class="card-content" style="display: grid">
    </div>
</div>

<script src="/libs/valine/av-min.js"></script>
<script src="/libs/valine/Valine.min.js"></script>
<script>
    new Valine({
        el: '#vcomments',
        appId: '5FkhQebEqGdoNnuL654mv5KM-gzGzoHsz',
        appKey: 'NNEBzCiygD4tBLqHt8diLxda',
        notify: 'true' === 'true',
        verify: 'true' === 'true',
        visitor: 'true' === 'true',
        avatar: 'mm',
        pageSize: '10',
        lang: 'zh-cn',
        placeholder: 'just go go'
    });
</script>

    

    

    

    

    

<article id="prenext-posts" class="prev-next articles">
    <div class="row article-row">
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge left-badge text-color">
                <i class="fas fa-chevron-left"></i>&nbsp;上一篇</div>
            <div class="card">
                <a href="/2020/11/23/mysql-ji-chu-bu-chong-yu-gao-ji/">
                    <div class="card-image">
                        
                        
                        <img src="/medias/featureimages/13.jpg" class="responsive-img" alt="Mysql基础补充与高级">
                        
                        <span class="card-title">Mysql基础补充与高级</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            对于mysql以前学过的基础进行复习，以及对于mysql高级的学习
                        
                    </div>
                    <div class="publish-info">
                        <span class="publish-date">
                            <i class="far fa-clock fa-fw icon-date"></i>2020-11-23
                        </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/categories/mysql/" class="post-category">
                                    mysql
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/tags/mysql/">
                        <span class="chip bg-color">mysql</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge right-badge text-color">
                下一篇&nbsp;<i class="fas fa-chevron-right"></i>
            </div>
            <div class="card">
                <a href="/2020/10/25/jvm-mian-shi-ti/">
                    <div class="card-image">
                        
                        
                        <img src="/medias/featureimages/20.jpg" class="responsive-img" alt="jvm面试题">
                        
                        <span class="card-title">jvm面试题</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            jvm的相关面试题
                        
                    </div>
                    <div class="publish-info">
                            <span class="publish-date">
                                <i class="far fa-clock fa-fw icon-date"></i>2020-10-25
                            </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/categories/jvm/" class="post-category">
                                    jvm
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/tags/jvm/">
                        <span class="chip bg-color">jvm</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
    </div>
</article>

</div>


<script>
    $('#articleContent').on('copy', function (e) {
        // IE8 or earlier browser is 'undefined'
        if (typeof window.getSelection === 'undefined') return;

        var selection = window.getSelection();
        // if the selection is short let's not annoy our users.
        if (('' + selection).length < Number.parseInt('120')) {
            return;
        }

        // create a div outside of the visible area and fill it with the selected text.
        var bodyElement = document.getElementsByTagName('body')[0];
        var newdiv = document.createElement('div');
        newdiv.style.position = 'absolute';
        newdiv.style.left = '-99999px';
        bodyElement.appendChild(newdiv);
        newdiv.appendChild(selection.getRangeAt(0).cloneContents());

        // we need a <pre> tag workaround.
        // otherwise the text inside "pre" loses all the line breaks!
        if (selection.getRangeAt(0).commonAncestorContainer.nodeName === 'PRE') {
            newdiv.innerHTML = "<pre>" + newdiv.innerHTML + "</pre>";
        }

        var url = document.location.href;
        newdiv.innerHTML += '<br />'
            + '来源: Max|Blog<br />'
            + '文章作者: Max<br />'
            + '文章链接: <a href="' + url + '">' + url + '</a><br />'
            + '本文章著作权归作者所有，任何形式的转载都请注明出处。';

        selection.selectAllChildren(newdiv);
        window.setTimeout(function () {bodyElement.removeChild(newdiv);}, 200);
    });
</script>


<!-- 代码块功能依赖 -->
<script type="text/javascript" src="/libs/codeBlock/codeBlockFuction.js"></script>

<!-- 代码语言 -->

<script type="text/javascript" src="/libs/codeBlock/codeLang.js"></script>


<!-- 代码块复制 -->

<script type="text/javascript" src="/libs/codeBlock/codeCopy.js"></script>


<!-- 代码块收缩 -->

<script type="text/javascript" src="/libs/codeBlock/codeShrink.js"></script>


    </div>
    <div id="toc-aside" class="expanded col l3 hide-on-med-and-down">
        <div class="toc-widget card" style="background-color: white;">
            <div class="toc-title"><i class="far fa-list-alt"></i>&nbsp;&nbsp;目录</div>
            <div id="toc-content"></div>
        </div>
    </div>
</div>

<!-- TOC 悬浮按钮. -->

<div id="floating-toc-btn" class="hide-on-med-and-down">
    <a class="btn-floating btn-large bg-color">
        <i class="fas fa-list-ul"></i>
    </a>
</div>


<script src="/libs/tocbot/tocbot.min.js"></script>
<script>
    $(function () {
        tocbot.init({
            tocSelector: '#toc-content',
            contentSelector: '#articleContent',
            headingsOffset: -($(window).height() * 0.4 - 45),
            collapseDepth: Number('0'),
            headingSelector: 'h2, h3, h4'
        });

        // modify the toc link href to support Chinese.
        let i = 0;
        let tocHeading = 'toc-heading-';
        $('#toc-content a').each(function () {
            $(this).attr('href', '#' + tocHeading + (++i));
        });

        // modify the heading title id to support Chinese.
        i = 0;
        $('#articleContent').children('h2, h3, h4').each(function () {
            $(this).attr('id', tocHeading + (++i));
        });

        // Set scroll toc fixed.
        let tocHeight = parseInt($(window).height() * 0.4 - 64);
        let $tocWidget = $('.toc-widget');
        $(window).scroll(function () {
            let scroll = $(window).scrollTop();
            /* add post toc fixed. */
            if (scroll > tocHeight) {
                $tocWidget.addClass('toc-fixed');
            } else {
                $tocWidget.removeClass('toc-fixed');
            }
        });

        
        /* 修复文章卡片 div 的宽度. */
        let fixPostCardWidth = function (srcId, targetId) {
            let srcDiv = $('#' + srcId);
            if (srcDiv.length === 0) {
                return;
            }

            let w = srcDiv.width();
            if (w >= 450) {
                w = w + 21;
            } else if (w >= 350 && w < 450) {
                w = w + 18;
            } else if (w >= 300 && w < 350) {
                w = w + 16;
            } else {
                w = w + 14;
            }
            $('#' + targetId).width(w);
        };

        // 切换TOC目录展开收缩的相关操作.
        const expandedClass = 'expanded';
        let $tocAside = $('#toc-aside');
        let $mainContent = $('#main-content');
        $('#floating-toc-btn .btn-floating').click(function () {
            if ($tocAside.hasClass(expandedClass)) {
                $tocAside.removeClass(expandedClass).hide();
                $mainContent.removeClass('l9');
            } else {
                $tocAside.addClass(expandedClass).show();
                $mainContent.addClass('l9');
            }
            fixPostCardWidth('artDetail', 'prenext-posts');
        });
        
    });
</script>

    

</main>


<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script>

    <footer class="page-footer bg-color">
    
        <link rel="stylesheet" href="/libs/aplayer/APlayer.min.css">
<style>
    .aplayer .aplayer-lrc p {
        
        display: none;
        
        font-size: 12px;
        font-weight: 700;
        line-height: 16px !important;
    }

    .aplayer .aplayer-lrc p.aplayer-lrc-current {
        
        display: none;
        
        font-size: 15px;
        color: #42b983;
    }

    
    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body {
        left: -66px !important;
    }

    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body:hover {
        left: 0px !important;
    }

    
</style>
<div class="">
    
    <div class="row">
        <meting-js class="col l8 offset-l2 m10 offset-m1 s12"
                   server="netease"
                   type="playlist"
                   id="2844914148"
                   fixed='true'
                   autoplay='false'
                   theme='#42b983'
                   loop='all'
                   order='random'
                   preload='auto'
                   volume='0.7'
                   list-folded='true'
        >
        </meting-js>
    </div>
</div>

<script src="/libs/aplayer/APlayer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js"></script>

    
    <div class="container row center-align" style="margin-bottom: 15px !important;">
        <div class="col s12 m8 l8 copy-right">
            Copyright&nbsp;&copy;
            
                <span id="year">2020-2021</span>
            
            <span id="year">2020</span>
            <a href="/about" target="_blank">Max</a>
            |&nbsp;Powered by&nbsp;<a href="https://hexo.io/" target="_blank">Hexo</a>
            |&nbsp;Theme&nbsp;<a href="https://github.com/blinkfox/hexo-theme-matery" target="_blank">Matery</a>
            <br>
            
            &nbsp;<i class="fas fa-chart-area"></i>&nbsp;站点总字数:&nbsp;<span
                class="white-color">141.4k</span>&nbsp;字
            
            
            
            
            
            
            <span id="busuanzi_container_site_pv">
                |&nbsp;<i class="far fa-eye"></i>&nbsp;总访问量:&nbsp;<span id="busuanzi_value_site_pv"
                    class="white-color"></span>&nbsp;次
            </span>
            
            
            <span id="busuanzi_container_site_uv">
                |&nbsp;<i class="fas fa-users"></i>&nbsp;总访问人数:&nbsp;<span id="busuanzi_value_site_uv"
                    class="white-color"></span>&nbsp;人
            </span>
            
            <br>
            
            <span id="sitetime">载入运行时间...</span>
            <script>
                function siteTime() {
                    var seconds = 1000;
                    var minutes = seconds * 60;
                    var hours = minutes * 60;
                    var days = hours * 24;
                    var years = days * 365;
                    var today = new Date();
                    var startYear = "2020";
                    var startMonth = "2";
                    var startDate = "13";
                    var startHour = "0";
                    var startMinute = "0";
                    var startSecond = "0";
                    var todayYear = today.getFullYear();
                    var todayMonth = today.getMonth() + 1;
                    var todayDate = today.getDate();
                    var todayHour = today.getHours();
                    var todayMinute = today.getMinutes();
                    var todaySecond = today.getSeconds();
                    var t1 = Date.UTC(startYear, startMonth, startDate, startHour, startMinute, startSecond);
                    var t2 = Date.UTC(todayYear, todayMonth, todayDate, todayHour, todayMinute, todaySecond);
                    var diff = t2 - t1;
                    var diffYears = Math.floor(diff / years);
                    var diffDays = Math.floor((diff / days) - diffYears * 365);
                    var diffHours = Math.floor((diff - (diffYears * 365 + diffDays) * days) / hours);
                    var diffMinutes = Math.floor((diff - (diffYears * 365 + diffDays) * days - diffHours * hours) /
                        minutes);
                    var diffSeconds = Math.floor((diff - (diffYears * 365 + diffDays) * days - diffHours * hours -
                        diffMinutes * minutes) / seconds);
                    if (startYear == todayYear) {
                        document.getElementById("year").innerHTML = todayYear;
                        document.getElementById("sitetime").innerHTML = "本站已安全运行 " + diffDays + " 天 " + diffHours +
                            " 小时 " + diffMinutes + " 分钟 " + diffSeconds + " 秒";
                    } else {
                        document.getElementById("year").innerHTML = startYear + " - " + todayYear;
                        document.getElementById("sitetime").innerHTML = "本站已安全运行 " + diffYears + " 年 " + diffDays +
                            " 天 " + diffHours + " 小时 " + diffMinutes + " 分钟 " + diffSeconds + " 秒";
                    }
                }
                setInterval(siteTime, 1000);
            </script>
            
            <br>
            
        </div>
        <div class="col s12 m4 l4 social-link social-statis">
    <a href="https://github.com/blinkfox" class="tooltipped" target="_blank" data-tooltip="访问我的GitHub" data-position="top" data-delay="50">
        <i class="fab fa-github"></i>
    </a>



    <a href="mailto:1181062873@qq.com" class="tooltipped" target="_blank" data-tooltip="邮件联系我" data-position="top" data-delay="50">
        <i class="fas fa-envelope-open"></i>
    </a>







    <a href="tencent://AddContact/?fromId=50&fromSubId=1&subcmd=all&uin=1181062873" class="tooltipped" target="_blank" data-tooltip="QQ联系我: 1181062873" data-position="top" data-delay="50">
        <i class="fab fa-qq"></i>
    </a>







    <a href="/atom.xml" class="tooltipped" target="_blank" data-tooltip="RSS 订阅" data-position="top" data-delay="50">
        <i class="fas fa-rss"></i>
    </a>

</div>
    </div>
</footer>

<div class="progress-bar"></div>


    <!-- 搜索遮罩框 -->
<div id="searchModal" class="modal">
    <div class="modal-content">
        <div class="search-header">
            <span class="title"><i class="fas fa-search"></i>&nbsp;&nbsp;搜索</span>
            <input type="search" id="searchInput" name="s" placeholder="请输入搜索的关键字"
                   class="search-input">
        </div>
        <div id="searchResult"></div>
    </div>
</div>

<script type="text/javascript">
$(function () {
    var searchFunc = function (path, search_id, content_id) {
        'use strict';
        $.ajax({
            url: path,
            dataType: "xml",
            success: function (xmlResponse) {
                // get the contents from search data
                var datas = $("entry", xmlResponse).map(function () {
                    return {
                        title: $("title", this).text(),
                        content: $("content", this).text(),
                        url: $("url", this).text()
                    };
                }).get();
                var $input = document.getElementById(search_id);
                var $resultContent = document.getElementById(content_id);
                $input.addEventListener('input', function () {
                    var str = '<ul class=\"search-result-list\">';
                    var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);
                    $resultContent.innerHTML = "";
                    if (this.value.trim().length <= 0) {
                        return;
                    }
                    // perform local searching
                    datas.forEach(function (data) {
                        var isMatch = true;
                        var data_title = data.title.trim().toLowerCase();
                        var data_content = data.content.trim().replace(/<[^>]+>/g, "").toLowerCase();
                        var data_url = data.url;
                        data_url = data_url.indexOf('/') === 0 ? data.url : '/' + data_url;
                        var index_title = -1;
                        var index_content = -1;
                        var first_occur = -1;
                        // only match artiles with not empty titles and contents
                        if (data_title !== '' && data_content !== '') {
                            keywords.forEach(function (keyword, i) {
                                index_title = data_title.indexOf(keyword);
                                index_content = data_content.indexOf(keyword);
                                if (index_title < 0 && index_content < 0) {
                                    isMatch = false;
                                } else {
                                    if (index_content < 0) {
                                        index_content = 0;
                                    }
                                    if (i === 0) {
                                        first_occur = index_content;
                                    }
                                }
                            });
                        }
                        // show search results
                        if (isMatch) {
                            str += "<li><a href='" + data_url + "' class='search-result-title'>" + data_title + "</a>";
                            var content = data.content.trim().replace(/<[^>]+>/g, "");
                            if (first_occur >= 0) {
                                // cut out 100 characters
                                var start = first_occur - 20;
                                var end = first_occur + 80;
                                if (start < 0) {
                                    start = 0;
                                }
                                if (start === 0) {
                                    end = 100;
                                }
                                if (end > content.length) {
                                    end = content.length;
                                }
                                var match_content = content.substr(start, end);
                                // highlight all keywords
                                keywords.forEach(function (keyword) {
                                    var regS = new RegExp(keyword, "gi");
                                    match_content = match_content.replace(regS, "<em class=\"search-keyword\">" + keyword + "</em>");
                                });

                                str += "<p class=\"search-result\">" + match_content + "...</p>"
                            }
                            str += "</li>";
                        }
                    });
                    str += "</ul>";
                    $resultContent.innerHTML = str;
                });
            }
        });
    };

    searchFunc('/search.xml', 'searchInput', 'searchResult');
});
</script>

    <!-- 回到顶部按钮 -->
<div id="backTop" class="top-scroll">
    <a class="btn-floating btn-large waves-effect waves-light" href="#!">
        <i class="fas fa-arrow-up"></i>
    </a>
</div>


    <script src="/libs/materialize/materialize.min.js"></script>
    <script src="/libs/masonry/masonry.pkgd.min.js"></script>
    <script src="/libs/aos/aos.js"></script>
    <script src="/libs/scrollprogress/scrollProgress.min.js"></script>
    <script src="/libs/lightGallery/js/lightgallery-all.min.js"></script>
    <script src="/js/matery.js"></script>

    <!-- Baidu Analytics -->

    <!-- Baidu Push -->

<script>
    (function () {
        var bp = document.createElement('script');
        var curProtocol = window.location.protocol.split(':')[0];
        if (curProtocol === 'https') {
            bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
        } else {
            bp.src = 'http://push.zhanzhang.baidu.com/push.js';
        }
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(bp, s);
    })();
</script>

    
    
    <script async src="/libs/others/busuanzi.pure.mini.js"></script>
    

    

    

    <!--腾讯兔小巢-->
    
    

    

    

    
    <script src="/libs/instantpage/instantpage.js" type="module"></script>
    

</body>

</html>
